o Add ipv6 support, abstracting most NCP addresses into opaque

structures (well, they're treated as opaque).

  It's now possible to manage IPv6 interface addresses and routing
  table entries and to filter IPV6 traffic whether encapsulated or
  not.

  IPV6CP support is crude for now, and hasn't been tested against
  any other implementations.

  RADIUS and IPv6 are independent of eachother for now.

  ppp.linkup/ppp.linkdown aren't currently used by IPV6CP

o Understand all protocols(5) in filter rules rather than only a select
  few.

o Allow a mask specification for the ``delete'' command.  It's now
  possible to specifically delete one of two conflicting routes.

o When creating and deleting proxy arp entries, do it for all IPv4
  interface addresses rather than doing it just for the ``current''
  peer address.

o When iface-alias isn't in effect, don't blow away manually (via ``iface
  add'') added interface addresses.

o When listening on a tcp server (diagnostic) socket, bind so that a
  tcp46 socket is created -- allowing both IPv4 and IPv6 connections.

o When displaying ICMP traffic, don't display the icmp type twice.
  When display traffic, display at least some information about unrecognised
  traffic.

o Bump version

Inspired after filtering work by: Makoto MATSUSHITA <matusita@jp.FreeBSD.org>
This commit is contained in:
Brian Somers 2001-08-14 16:05:52 +00:00
parent 135047c346
commit 30949fd4b5
50 changed files with 4427 additions and 1933 deletions

View File

@ -4,10 +4,10 @@ PROG= ppp
MAN= ppp.8
SRCS= acf.c arp.c async.c auth.c bundle.c cbcp.c ccp.c chap.c chat.c \
command.c datalink.c deflate.c defs.c exec.c filter.c fsm.c hdlc.c \
iface.c ip.c ipcp.c iplist.c lcp.c link.c log.c lqr.c main.c \
mbuf.c mp.c pap.c physical.c pred.c probe.c prompt.c proto.c route.c \
server.c sig.c slcompress.c sync.c systems.c tcp.c tcpmss.c \
throughput.c timer.c tty.c tun.c udp.c vjcomp.c
iface.c ip.c ipcp.c ipv6cp.c iplist.c lcp.c link.c log.c lqr.c main.c \
mbuf.c mp.c ncp.c ncpaddr.c pap.c physical.c pred.c probe.c prompt.c \
proto.c route.c server.c sig.c slcompress.c sync.c systems.c tcp.c \
tcpmss.c throughput.c timer.c tty.c tun.c udp.c vjcomp.c
.if defined(NOSUID) || defined(PPP_NOSUID)
BINMODE=554
.else

View File

@ -57,13 +57,16 @@
#include "slcompress.h"
#include "lqr.h"
#include "hdlc.h"
#include "ncpaddr.h"
#include "ipcp.h"
#include "filter.h"
#include "ipv6cp.h"
#include "descriptor.h"
#include "lcp.h"
#include "ccp.h"
#include "link.h"
#include "mp.h"
#include "ncp.h"
#include "filter.h"
#ifndef NORADIUS
#include "radius.h"
#endif

View File

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pwd.h>
@ -51,6 +52,8 @@
#include "slcompress.h"
#include "lqr.h"
#include "hdlc.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "auth.h"
#include "systems.h"
@ -70,6 +73,8 @@
#include "async.h"
#include "physical.h"
#include "datalink.h"
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
const char *

View File

@ -71,6 +71,8 @@
#include "hdlc.h"
#include "throughput.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -82,6 +84,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "async.h"
#include "physical.h"
@ -93,7 +97,6 @@
#include "chat.h"
#include "cbcp.h"
#include "datalink.h"
#include "ip.h"
#include "iface.h"
#include "server.h"
#ifdef HAVE_DES
@ -147,10 +150,13 @@ bundle_NewPhase(struct bundle *bundle, u_int new)
break;
case PHASE_NETWORK:
fsm_Up(&bundle->ncp.ipcp.fsm);
fsm_Open(&bundle->ncp.ipcp.fsm);
bundle->phase = new;
log_DisplayPrompts();
if (ncp_fsmStart(&bundle->ncp, bundle)) {
bundle->phase = new;
log_DisplayPrompts();
} else {
log_Printf(LogPHASE, "bundle: All NCPs are disabled\n");
bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
}
break;
case PHASE_TERMINATE:
@ -214,8 +220,7 @@ bundle_ClearQueues(void *v)
* dictionaries in use (causing the relevant RESET_REQ/RESET_ACK).
*/
ip_DeleteQueue(&bundle->ncp.ipcp);
mp_DeleteQueue(&bundle->ncp.mp);
ncp_DeleteQueues(&bundle->ncp);
for (dl = bundle->links; dl; dl = dl->next)
physical_DeleteQueue(dl->physical);
}
@ -270,12 +275,14 @@ bundle_LayerUp(void *v, struct fsm *fp)
bundle_LinkAdded(bundle, p->dl);
mp_CheckAutoloadTimer(&bundle->ncp.mp);
} else if (fp->proto == PROTO_IPCP) {
bundle_CalculateBandwidth(fp->bundle);
time(&bundle->upat);
bundle_StartIdleTimer(bundle, 0);
} else if (isncp(fp->proto)) {
if (ncp_LayersOpen(&fp->bundle->ncp) == 1) {
bundle_CalculateBandwidth(fp->bundle);
time(&bundle->upat);
bundle_StartIdleTimer(bundle, 0);
mp_CheckAutoloadTimer(&fp->bundle->ncp.mp);
}
bundle_Notify(bundle, EX_NORMAL);
mp_CheckAutoloadTimer(&fp->bundle->ncp.mp);
} else if (fp->proto == PROTO_CCP)
bundle_CalculateBandwidth(fp->bundle); /* Against ccp_MTUOverhead */
}
@ -296,10 +303,12 @@ bundle_LayerDown(void *v, struct fsm *fp)
struct bundle *bundle = (struct bundle *)v;
if (fp->proto == PROTO_IPCP) {
bundle_StopIdleTimer(bundle);
bundle->upat = 0;
mp_StopAutoloadTimer(&bundle->ncp.mp);
if (isncp(fp->proto)) {
if (ncp_LayersOpen(&fp->bundle->ncp) == 0) {
bundle_StopIdleTimer(bundle);
bundle->upat = 0;
mp_StopAutoloadTimer(&bundle->ncp.mp);
}
} else if (fp->proto == PROTO_LCP) {
struct datalink *dl;
struct datalink *lost;
@ -328,7 +337,7 @@ bundle_LayerDown(void *v, struct fsm *fp)
if (!others_active)
/* Down the NCPs. We don't expect to get fsm_Close()d ourself ! */
fsm2initial(&bundle->ncp.ipcp.fsm);
ncp2initial(&bundle->ncp);
}
}
@ -343,7 +352,7 @@ bundle_LayerFinish(void *v, struct fsm *fp)
struct bundle *bundle = (struct bundle *)v;
struct datalink *dl;
if (fp->proto == PROTO_IPCP) {
if (isncp(fp->proto) && !ncp_LayersUnfinished(&bundle->ncp)) {
if (bundle_Phase(bundle) != PHASE_DEAD)
bundle_NewPhase(bundle, PHASE_TERMINATE);
for (dl = bundle->links; dl; dl = dl->next)
@ -353,12 +362,6 @@ bundle_LayerFinish(void *v, struct fsm *fp)
}
}
int
bundle_LinkIsUp(const struct bundle *bundle)
{
return bundle->ncp.ipcp.fsm.state == ST_OPENED;
}
void
bundle_Close(struct bundle *bundle, const char *name, int how)
{
@ -398,11 +401,10 @@ bundle_Close(struct bundle *bundle, const char *name, int how)
if (!others_active) {
bundle_StopIdleTimer(bundle);
if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
bundle->ncp.ipcp.fsm.state == ST_STARTING)
fsm_Close(&bundle->ncp.ipcp.fsm);
if (ncp_LayersUnfinished(&bundle->ncp))
ncp_Close(&bundle->ncp);
else {
fsm2initial(&bundle->ncp.ipcp.fsm);
ncp2initial(&bundle->ncp);
for (dl = bundle->links; dl; dl = dl->next)
datalink_Close(dl, how);
}
@ -420,29 +422,6 @@ bundle_Down(struct bundle *bundle, int how)
datalink_Down(dl, how);
}
static size_t
bundle_FillQueues(struct bundle *bundle)
{
size_t total;
if (bundle->ncp.mp.active)
total = mp_FillQueues(bundle);
else {
struct datalink *dl;
size_t add;
for (total = 0, dl = bundle->links; dl; dl = dl->next)
if (dl->state == DATALINK_OPEN) {
add = link_QueueLen(&dl->physical->link);
if (add == 0 && dl->physical->out == NULL)
add = ip_PushPacket(&dl->physical->link, bundle);
total += add;
}
}
return total + ip_QueueLen(&bundle->ncp.ipcp);
}
static int
bundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
{
@ -459,7 +438,8 @@ bundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
nlinks++;
if (nlinks) {
queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp);
queued = r ? ncp_FillPhysicalQueues(&bundle->ncp, bundle) :
ncp_QueueLen(&bundle->ncp);
if (r && (bundle->phase == PHASE_NETWORK ||
bundle->phys_type.all & PHYS_AUTO)) {
@ -529,6 +509,7 @@ bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
{
struct datalink *dl;
unsigned secs;
u_int32_t af;
if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset);
@ -571,16 +552,23 @@ bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
bundle->dev.Name, n);
return;
}
if (ntohl(tun.header.family) != AF_INET)
af = ntohl(tun.header.family);
#ifndef NOINET6
if (af != AF_INET && af != AF_INET6)
#else
if (af != AF_INET)
#endif
/* XXX: Should be maintaining drop/family counts ! */
return;
}
} else
af = AF_INET;
if (((struct ip *)tun.data)->ip_dst.s_addr ==
if (af == AF_INET && ((struct ip *)tun.data)->ip_dst.s_addr ==
bundle->ncp.ipcp.my_ip.s_addr) {
/* we've been asked to send something addressed *to* us :( */
if (Enabled(bundle, OPT_LOOPBACK)) {
pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in, NULL, NULL);
pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.in,
NULL, NULL);
if (pri >= 0) {
n += sz - sizeof tun.data;
write(bundle->dev.fd, data, n);
@ -592,8 +580,8 @@ bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
}
/*
* Process on-demand dialup. Output packets are queued within tunnel
* device until IPCP is opened.
* Process on-demand dialup. Output packets are queued within the tunnel
* device until the appropriate NCP is opened.
*/
if (bundle_Phase(bundle) == PHASE_DEAD) {
@ -601,7 +589,8 @@ bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
* Note, we must be in AUTO mode :-/ otherwise our interface should
* *not* be UP and we can't receive data
*/
pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial, NULL, NULL);
pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.dial,
NULL, NULL);
if (pri >= 0)
bundle_Open(bundle, NULL, PHYS_AUTO, 0);
else
@ -616,11 +605,12 @@ bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
}
secs = 0;
pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out, NULL, &secs);
pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.out,
NULL, &secs);
if (pri >= 0) {
/* Prepend the number of seconds timeout given in the filter */
tun.header.timeout = secs;
ip_Enqueue(&bundle->ncp.ipcp, pri, (char *)&tun, n + sizeof tun.header);
ncp_Enqueue(&bundle->ncp, af, pri, (char *)&tun, n + sizeof tun.header);
}
}
}
@ -818,7 +808,10 @@ bundle_Create(const char *prefix, int type, int unit)
bundle.cfg.idle.min_timeout = 0;
*bundle.cfg.auth.name = '\0';
*bundle.cfg.auth.key = '\0';
bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | OPT_TCPMSSFIXUP |
bundle.cfg.opt = OPT_IDCHECK | OPT_LOOPBACK | OPT_SROUTES | OPT_TCPMSSFIXUP |
#ifndef NOINET6
OPT_IPCP | OPT_IPV6CP |
#endif
OPT_THROUGHPUT | OPT_UTMP;
*bundle.cfg.label = '\0';
bundle.cfg.ifqueue = DEF_IFQUEUE;
@ -842,11 +835,7 @@ bundle_Create(const char *prefix, int type, int unit)
bundle.desc.Read = bundle_DescriptorRead;
bundle.desc.Write = bundle_DescriptorWrite;
mp_Init(&bundle.ncp.mp, &bundle);
/* Send over the first physical link by default */
ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
&bundle.fsm);
ncp_Init(&bundle.ncp, &bundle);
memset(&bundle.filter, '\0', sizeof bundle.filter);
bundle.filter.in.fragok = bundle.filter.in.logok = 1;
@ -875,7 +864,7 @@ bundle_Create(const char *prefix, int type, int unit)
#endif
/* Clean out any leftover crud */
iface_Clear(bundle.iface, IFACE_CLEAR_ALL);
iface_Clear(bundle.iface, &bundle.ncp, 0, IFACE_CLEAR_ALL);
bundle_LockTun(&bundle);
@ -895,19 +884,18 @@ bundle_Destroy(struct bundle *bundle)
struct datalink *dl;
/*
* Clean up the interface. We don't need to timer_Stop()s, mp_Down(),
* ipcp_CleanInterface() and bundle_DownInterface() unless we're getting
* Clean up the interface. We don't really need to do the timer_Stop()s,
* mp_Down(), iface_Clear() and bundle_DownInterface() unless we're getting
* out under exceptional conditions such as a descriptor exception.
*/
timer_Stop(&bundle->idle.timer);
timer_Stop(&bundle->choked.timer);
mp_Down(&bundle->ncp.mp);
ipcp_CleanInterface(&bundle->ncp.ipcp);
iface_Clear(bundle->iface, &bundle->ncp, 0, IFACE_CLEAR_ALL);
bundle_DownInterface(bundle);
#ifndef NORADIUS
/* Tell the radius server the bad news */
log_Printf(LogDEBUG, "Radius: Destroy called from bundle_Destroy\n");
radius_Destroy(&bundle->radius);
#endif
@ -916,7 +904,7 @@ bundle_Destroy(struct bundle *bundle)
while (dl)
dl = datalink_Destroy(dl);
ipcp_Destroy(&bundle->ncp.ipcp);
ncp_Destroy(&bundle->ncp);
close(bundle->dev.fd);
bundle_UnlockTun(bundle);
@ -953,7 +941,7 @@ bundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
if (!other_links) {
if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */
bundle_DownInterface(bundle);
fsm2initial(&bundle->ncp.ipcp.fsm);
ncp2initial(&bundle->ncp);
bundle_NewPhase(bundle, PHASE_DEAD);
bundle_StopIdleTimer(bundle);
}
@ -1056,7 +1044,7 @@ bundle_ShowStatus(struct cmdargs const *arg)
(secs / 60) % 60, secs % 60);
}
prompt_Printf(arg->prompt, "\n Queued: %lu of %u\n",
(unsigned long)ip_QueueLen(&arg->bundle->ncp.ipcp),
(unsigned long)ncp_QueueLen(&arg->bundle->ncp),
arg->bundle->cfg.ifqueue);
prompt_Printf(arg->prompt, "\nDefaults:\n");
@ -1096,23 +1084,18 @@ bundle_ShowStatus(struct cmdargs const *arg)
} else
prompt_Printf(arg->prompt, "disabled\n");
prompt_Printf(arg->prompt, " sendpipe: ");
if (arg->bundle->ncp.ipcp.cfg.sendpipe > 0)
prompt_Printf(arg->prompt, "%-20ld", arg->bundle->ncp.ipcp.cfg.sendpipe);
else
prompt_Printf(arg->prompt, "unspecified ");
prompt_Printf(arg->prompt, " recvpipe: ");
if (arg->bundle->ncp.ipcp.cfg.recvpipe > 0)
prompt_Printf(arg->prompt, "%ld\n", arg->bundle->ncp.ipcp.cfg.recvpipe);
else
prompt_Printf(arg->prompt, "unspecified\n");
prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s",
optval(arg->bundle, OPT_SROUTES));
prompt_Printf(arg->prompt, " Filter Decap: %s\n",
prompt_Printf(arg->prompt, " Filter Decap: %-20.20s",
optval(arg->bundle, OPT_FILTERDECAP));
prompt_Printf(arg->prompt, " ID check: %-20.20s",
prompt_Printf(arg->prompt, " ID check: %s\n",
optval(arg->bundle, OPT_IDCHECK));
prompt_Printf(arg->prompt, " Iface-Alias: %-20.20s",
optval(arg->bundle, OPT_IFACEALIAS));
#ifndef NOINET6
prompt_Printf(arg->prompt, " IPCP: %s\n",
optval(arg->bundle, OPT_IPCP));
prompt_Printf(arg->prompt, " IPV6CP: %-20.20s",
optval(arg->bundle, OPT_IPV6CP));
#endif
prompt_Printf(arg->prompt, " Keep-Session: %s\n",
optval(arg->bundle, OPT_KEEPSESSION));
prompt_Printf(arg->prompt, " Loopback: %-20.20s",
@ -1123,14 +1106,14 @@ bundle_ShowStatus(struct cmdargs const *arg)
optval(arg->bundle, OPT_PROXY));
prompt_Printf(arg->prompt, " Proxyall: %s\n",
optval(arg->bundle, OPT_PROXYALL));
prompt_Printf(arg->prompt, " TCPMSS Fixup: %-20.20s",
prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s",
optval(arg->bundle, OPT_SROUTES));
prompt_Printf(arg->prompt, " TCPMSS Fixup: %s\n",
optval(arg->bundle, OPT_TCPMSSFIXUP));
prompt_Printf(arg->prompt, " Throughput: %s\n",
prompt_Printf(arg->prompt, " Throughput: %-20.20s",
optval(arg->bundle, OPT_THROUGHPUT));
prompt_Printf(arg->prompt, " Utmp Logging: %-20.20s",
prompt_Printf(arg->prompt, " Utmp Logging: %s\n",
optval(arg->bundle, OPT_UTMP));
prompt_Printf(arg->prompt, " Iface-Alias: %s\n",
optval(arg->bundle, OPT_IFACEALIAS));
return 0;
}
@ -1183,7 +1166,7 @@ bundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout)
bundle->cfg.idle.timeout = timeout;
if (min_timeout >= 0)
bundle->cfg.idle.min_timeout = min_timeout;
if (bundle_LinkIsUp(bundle))
if (ncp_LayersOpen(&bundle->ncp))
bundle_StartIdleTimer(bundle, 0);
}
@ -1795,18 +1778,20 @@ bundle_Exception(struct bundle *bundle, int fd)
}
void
bundle_AdjustFilters(struct bundle *bundle, struct in_addr *my_ip,
struct in_addr *peer_ip)
bundle_AdjustFilters(struct bundle *bundle, struct ncpaddr *local,
struct ncpaddr *remote)
{
filter_AdjustAddr(&bundle->filter.in, my_ip, peer_ip, NULL);
filter_AdjustAddr(&bundle->filter.out, my_ip, peer_ip, NULL);
filter_AdjustAddr(&bundle->filter.dial, my_ip, peer_ip, NULL);
filter_AdjustAddr(&bundle->filter.alive, my_ip, peer_ip, NULL);
filter_AdjustAddr(&bundle->filter.in, local, remote, NULL);
filter_AdjustAddr(&bundle->filter.out, local, remote, NULL);
filter_AdjustAddr(&bundle->filter.dial, local, remote, NULL);
filter_AdjustAddr(&bundle->filter.alive, local, remote, NULL);
}
void
bundle_AdjustDNS(struct bundle *bundle, struct in_addr dns[2])
bundle_AdjustDNS(struct bundle *bundle)
{
struct in_addr *dns = bundle->ncp.ipcp.ns.dns;
filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns);
filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns);
filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns);

View File

@ -36,15 +36,19 @@
#define OPT_FILTERDECAP 0x0001
#define OPT_IDCHECK 0x0002
#define OPT_IFACEALIAS 0x0004
#define OPT_KEEPSESSION 0x0008
#define OPT_LOOPBACK 0x0010
#define OPT_PASSWDAUTH 0x0020
#define OPT_PROXY 0x0040
#define OPT_PROXYALL 0x0080
#define OPT_SROUTES 0x0100
#define OPT_TCPMSSFIXUP 0x0200
#define OPT_THROUGHPUT 0x0400
#define OPT_UTMP 0x0800
#ifndef NOINET6
#define OPT_IPCP 0x0008
#define OPT_IPV6CP 0x0010
#endif
#define OPT_KEEPSESSION 0x0020
#define OPT_LOOPBACK 0x0040
#define OPT_PASSWDAUTH 0x0080
#define OPT_PROXY 0x0100
#define OPT_PROXYALL 0x0200
#define OPT_SROUTES 0x0400
#define OPT_TCPMSSFIXUP 0x0800
#define OPT_THROUGHPUT 0x1000
#define OPT_UTMP 0x2000
#define MAX_ENDDISC_CLASS 5
@ -109,10 +113,7 @@ struct bundle {
} choked;
} cfg;
struct {
struct ipcp ipcp; /* Our IPCP FSM */
struct mp mp; /* Our MP */
} ncp;
struct ncp ncp;
struct {
struct filter in; /* incoming packet filter */
@ -149,7 +150,6 @@ extern const char *bundle_PhaseName(struct bundle *);
#define bundle_Phase(b) ((b)->phase)
extern void bundle_NewPhase(struct bundle *, u_int);
extern void bundle_LinksRemoved(struct bundle *);
extern int bundle_LinkIsUp(const struct bundle *);
extern void bundle_Close(struct bundle *, const char *, int);
extern void bundle_Down(struct bundle *, int);
extern void bundle_Open(struct bundle *, const char *, int, int);
@ -184,9 +184,9 @@ extern void bundle_setsid(struct bundle *, int);
extern void bundle_LockTun(struct bundle *);
extern int bundle_HighestState(struct bundle *);
extern int bundle_Exception(struct bundle *, int);
extern void bundle_AdjustFilters(struct bundle *, struct in_addr *,
struct in_addr *);
extern void bundle_AdjustDNS(struct bundle *, struct in_addr [2]);
extern void bundle_AdjustFilters(struct bundle *, struct ncpaddr *,
struct ncpaddr *);
extern void bundle_AdjustDNS(struct bundle *);
extern void bundle_CalculateBandwidth(struct bundle *);
extern void bundle_AutoAdjust(struct bundle *, int, int);
extern int bundle_WantAutoloadTimer(struct bundle *);

View File

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
@ -56,6 +57,8 @@
#include "hdlc.h"
#include "lcp.h"
#include "ccp.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -70,6 +73,8 @@
#ifdef HAVE_DES
#include "mppe.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
static void CcpSendConfigReq(struct fsm *);

View File

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
@ -66,6 +67,8 @@
#include "chap.h"
#include "iplist.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "ccp.h"
@ -75,6 +78,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "chat.h"
#include "cbcp.h"

View File

@ -30,6 +30,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
@ -63,6 +64,8 @@
#include "chap.h"
#include "slcompress.h"
#include "iplist.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "cbcp.h"
@ -71,6 +74,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "id.h"

View File

@ -70,6 +70,8 @@
#include "lqr.h"
#include "hdlc.h"
#include "lcp.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#ifndef NONAT
#include "nat_cmd.h"
@ -88,6 +90,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "server.h"
#include "prompt.h"
@ -159,7 +163,7 @@
#define NEG_MPPE 54
#define NEG_CHAP81 55
const char Version[] = "2.3.2";
const char Version[] = "3.0.0";
static int ShowCommand(struct cmdargs const *);
static int TerminalCommand(struct cmdargs const *);
@ -454,9 +458,17 @@ command_Expand(char **nargv, int argc, char const *const *oargv,
nargv[arg] = strdup(oargv[arg]);
nargv[arg] = subst(nargv[arg], "HISADDR",
inet_ntoa(bundle->ncp.ipcp.peer_ip));
#ifndef NOINET6
nargv[arg] = subst(nargv[arg], "HISADDR6",
ncpaddr_ntoa(&bundle->ncp.ipv6cp.hisaddr));
#endif
nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
#ifndef NOINET6
nargv[arg] = subst(nargv[arg], "MYADDR6",
ncpaddr_ntoa(&bundle->ncp.ipv6cp.myaddr));
#endif
nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
@ -676,7 +688,7 @@ static struct cmdtab const IfaceCommands[] =
"Add or change an iface address", "iface add! addr[/bits| mask] peer",
(void *)1},
{"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
"Clear iface address(es)", "iface clear"},
"Clear iface address(es)", "iface clear [INET | INET6]"},
{"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
"Delete iface address", "iface delete addr", NULL},
{NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
@ -703,7 +715,7 @@ static struct cmdtab const Commands[] = {
"Run a background command", "[!]bg command"},
{"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
"Clear throughput statistics",
"clear ipcp|physical [current|overall|peak]..."},
"clear ipcp|ipv6cp|physical [current|overall|peak]..."},
{"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
"Clone a link", "clone newname..."},
{"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
@ -845,6 +857,10 @@ static struct cmdtab const ShowCommands[] = {
"Interface status", "show iface"},
{"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
"IPCP status", "show ipcp"},
#ifndef NOINET6
{"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
"IPV6CP status", "show ipv6cp"},
#endif
{"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
"Protocol layers", "show layers"},
{"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
@ -857,6 +873,8 @@ static struct cmdtab const ShowCommands[] = {
"log levels", "show log"},
{"mem", NULL, mbuf_Show, LOCAL_AUTH,
"mbuf allocations", "show mem"},
{"ncp", NULL, ncp_Show, LOCAL_AUTH,
"NCP status", "show ncp"},
{"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
"(low-level) link info", "show physical"},
{"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
@ -1404,43 +1422,42 @@ SetEscape(struct cmdargs const *arg)
static int
SetInterfaceAddr(struct cmdargs const *arg)
{
struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
struct ncp *ncp = &arg->bundle->ncp;
struct ncpaddr ncpaddr;
const char *hisaddr;
if (arg->argc > arg->argn + 4)
return -1;
hisaddr = NULL;
memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
ipcp->cfg.HaveTriggerAddress = 0;
ipcp->cfg.netmask.s_addr = INADDR_ANY;
iplist_reset(&ipcp->cfg.peer_list);
memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
ncp->ipcp.cfg.HaveTriggerAddress = 0;
ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
iplist_reset(&ncp->ipcp.cfg.peer_list);
if (arg->argc > arg->argn) {
if (!ParseAddr(ipcp, arg->argv[arg->argn],
&ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
&ipcp->cfg.my_range.width))
if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
return 1;
if (arg->argc > arg->argn+1) {
hisaddr = arg->argv[arg->argn+1];
if (arg->argc > arg->argn+2) {
ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
GetIpAddr(arg->argv[arg->argn+2]);
if (arg->argc > arg->argn+3) {
ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
ipcp->cfg.HaveTriggerAddress = 1;
ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
ncp->ipcp.cfg.HaveTriggerAddress = 1;
}
}
}
}
/* 0.0.0.0 means any address (0 bits) */
if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
ipcp->cfg.my_range.width = 0;
}
ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL);
ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
arg->bundle->phys_type.all & PHYS_AUTO))
@ -1499,7 +1516,8 @@ SetVariable(struct cmdargs const *arg)
const char *argp;
struct datalink *cx = arg->cx; /* LOCAL_CX uses this */
struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */
struct in_addr dummyaddr, *addr;
struct in_addr *ipaddr;
struct ncpaddr ncpaddr[2];
if (arg->argc > arg->argn)
argp = arg->argv[arg->argn];
@ -1929,27 +1947,30 @@ SetVariable(struct cmdargs const *arg)
case VAR_NBNS:
case VAR_DNS:
if (param == VAR_DNS) {
addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
addr[0].s_addr = addr[1].s_addr = INADDR_NONE;
ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
} else {
addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
}
if (arg->argc > arg->argn) {
ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
addr, &dummyaddr, &dummyint);
if (arg->argc > arg->argn+1)
ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
addr + 1, &dummyaddr, &dummyint);
if (addr[0].s_addr == INADDR_ANY) {
addr[0].s_addr = addr[1].s_addr;
addr[1].s_addr = INADDR_ANY;
ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
if (!ncpaddr_getip4(ncpaddr, ipaddr))
return -1;
if (arg->argc > arg->argn+1) {
ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
return -1;
}
if (addr[0].s_addr == INADDR_NONE) {
addr[0].s_addr = addr[1].s_addr;
addr[1].s_addr = INADDR_NONE;
if (ipaddr[0].s_addr == INADDR_ANY) {
ipaddr[0] = ipaddr[1];
ipaddr[1].s_addr = INADDR_ANY;
}
if (ipaddr[0].s_addr == INADDR_NONE) {
ipaddr[0] = ipaddr[1];
ipaddr[1].s_addr = INADDR_NONE;
}
}
break;
@ -2011,12 +2032,12 @@ SetVariable(struct cmdargs const *arg)
case VAR_SENDPIPE:
long_val = atol(argp);
arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
arg->bundle->ncp.cfg.sendpipe = long_val;
break;
case VAR_RECVPIPE:
long_val = atol(argp);
arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
arg->bundle->ncp.cfg.recvpipe = long_val;
break;
#ifndef NORADIUS
@ -2075,45 +2096,43 @@ SetVariable(struct cmdargs const *arg)
case VAR_URGENTPORTS:
if (arg->argn == arg->argc) {
ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
ncp_SetUrgentTOS(&arg->bundle->ncp);
ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
} else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
ncp_SetUrgentTOS(&arg->bundle->ncp);
if (arg->argn == arg->argc - 1)
ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
else for (f = arg->argn + 1; f < arg->argc; f++)
if (*arg->argv[f] == '+')
ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
else if (*arg->argv[f] == '-')
ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp,
atoi(arg->argv[f] + 1));
ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
else {
if (f == arg->argn)
ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
}
} else if (arg->argn == arg->argc - 1 &&
!strcasecmp(arg->argv[arg->argn], "none")) {
ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
ipcp_ClearUrgentTOS(&arg->bundle->ncp.ipcp);
ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
ncp_ClearUrgentTOS(&arg->bundle->ncp);
} else {
ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
ncp_SetUrgentTOS(&arg->bundle->ncp);
first = arg->argn;
if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
for (f = first; f < arg->argc; f++)
if (*arg->argv[f] == '+')
ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
else if (*arg->argv[f] == '-')
ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp,
atoi(arg->argv[f] + 1));
ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
else {
if (f == first)
ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
}
}
break;
@ -2173,7 +2192,7 @@ static struct cmdtab const SetCommands[] = {
"escape characters", "set escape hex-digit ..."},
{"filter", NULL, filter_Set, LOCAL_AUTH,
"packet filters", "set filter alive|dial|in|out rule-no permit|deny "
"[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp "
"[src_addr[/width]] [dst_addr[/width]] [proto "
"[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
{"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
"hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
@ -2261,73 +2280,84 @@ SetCommand(struct cmdargs const *arg)
static int
AddCommand(struct cmdargs const *arg)
{
struct in_addr dest, gateway, netmask;
int gw, addrs;
struct ncpaddr gw;
struct ncprange dest;
struct in_addr host;
int dest_default, gw_arg, addrs;
if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
return -1;
addrs = 0;
if (arg->argc == arg->argn+2) {
dest_default = 0;
if (arg->argc == arg->argn + 2) {
if (!strcasecmp(arg->argv[arg->argn], "default"))
dest.s_addr = netmask.s_addr = INADDR_ANY;
dest_default = 1;
else {
int width;
if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
&dest, &netmask, &width))
if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
return -1;
if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
addrs = ROUTE_DSTMYADDR;
else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
addrs = ROUTE_DSTMYADDR6;
else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
addrs = ROUTE_DSTHISADDR;
else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
addrs = ROUTE_DSTHISADDR6;
else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
addrs = ROUTE_DSTDNS0;
else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
addrs = ROUTE_DSTDNS1;
}
gw = 1;
gw_arg = 1;
} else {
if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
addrs = ROUTE_DSTMYADDR;
dest = arg->bundle->ncp.ipcp.my_ip;
host = arg->bundle->ncp.ipcp.my_ip;
} else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
addrs = ROUTE_DSTHISADDR;
dest = arg->bundle->ncp.ipcp.peer_ip;
host = arg->bundle->ncp.ipcp.peer_ip;
} else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
addrs = ROUTE_DSTDNS0;
dest = arg->bundle->ncp.ipcp.ns.dns[0];
host = arg->bundle->ncp.ipcp.ns.dns[0];
} else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
addrs = ROUTE_DSTDNS1;
dest = arg->bundle->ncp.ipcp.ns.dns[1];
host = arg->bundle->ncp.ipcp.ns.dns[1];
} else {
dest = GetIpAddr(arg->argv[arg->argn]);
if (dest.s_addr == INADDR_NONE) {
host = GetIpAddr(arg->argv[arg->argn]);
if (host.s_addr == INADDR_NONE) {
log_Printf(LogWARN, "%s: Invalid destination address\n",
arg->argv[arg->argn]);
return -1;
}
}
netmask = GetIpAddr(arg->argv[arg->argn+1]);
gw = 2;
ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
gw_arg = 2;
}
if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
gateway = arg->bundle->ncp.ipcp.peer_ip;
if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
addrs |= ROUTE_GWHISADDR;
#ifndef NOINET6
} else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
ncpaddr_copy(&gw, &arg->bundle->ncp.ipv6cp.hisaddr);
addrs |= ROUTE_GWHISADDR6;
#endif
} else {
gateway = GetIpAddr(arg->argv[arg->argn+gw]);
if (gateway.s_addr == INADDR_NONE) {
if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
log_Printf(LogWARN, "%s: Invalid gateway address\n",
arg->argv[arg->argn + gw]);
arg->argv[arg->argn + gw_arg]);
return -1;
}
}
if (rt_Set(arg->bundle, RTM_ADD, dest, gateway, netmask,
arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
if (dest_default)
ncprange_setdefault(&dest, ncpaddr_family(&gw));
if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
&& addrs != ROUTE_STATIC)
route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
return 0;
}
@ -2335,39 +2365,43 @@ AddCommand(struct cmdargs const *arg)
static int
DeleteCommand(struct cmdargs const *arg)
{
struct in_addr dest, none;
struct ncprange dest;
int addrs;
if (arg->argc == arg->argn+1) {
if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
route_IfDelete(arg->bundle, 0);
route_DeleteAll(&arg->bundle->ncp.ipcp.route);
route_DeleteAll(&arg->bundle->ncp.route);
} else {
addrs = 0;
if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
dest = arg->bundle->ncp.ipcp.my_ip;
ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
addrs = ROUTE_DSTMYADDR;
#ifndef NOINET6
} else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
addrs = ROUTE_DSTMYADDR6;
#endif
} else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
dest = arg->bundle->ncp.ipcp.peer_ip;
ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
addrs = ROUTE_DSTHISADDR;
#ifndef NOINET6
} else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
addrs = ROUTE_DSTHISADDR6;
#endif
} else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
dest = arg->bundle->ncp.ipcp.ns.dns[0];
ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
addrs = ROUTE_DSTDNS0;
} else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
dest = arg->bundle->ncp.ipcp.ns.dns[1];
ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
addrs = ROUTE_DSTDNS1;
} else {
dest = GetIpAddr(arg->argv[arg->argn]);
if (dest.s_addr == INADDR_NONE) {
log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]);
return -1;
}
ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
addrs = ROUTE_STATIC;
}
none.s_addr = INADDR_ANY;
rt_Set(arg->bundle, RTM_DELETE, dest, none, none,
arg->cmd->args ? 1 : 0, 0);
route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
route_Delete(&arg->bundle->ncp.route, addrs, &dest);
}
} else
return -1;
@ -2685,6 +2719,12 @@ static struct cmdtab const NegotiateCommands[] = {
{"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
"retain interface addresses", "disable|enable",
(const void *)OPT_IFACEALIAS},
#ifndef NOINET6
{"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
"disable|enable", (const void *)OPT_IPCP},
{"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
"disable|enable", (const void *)OPT_IPV6CP},
#endif
{"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
"disable|enable", (const void *)OPT_KEEPSESSION},
{"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
@ -2704,7 +2744,11 @@ static struct cmdtab const NegotiateCommands[] = {
{"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
"disable|enable", (const void *)OPT_UTMP},
#define OPT_MAX 11 /* accept/deny allowed below and not above */
#ifndef NOINET6
#define OPT_MAX 13 /* accept/deny allowed below and not above */
#else
#define OPT_MAX 11
#endif
{"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
"Address & Control field compression", "accept|deny|disable|enable",
@ -2819,6 +2863,10 @@ ClearCommand(struct cmdargs const *arg)
t = &cx->physical->link.stats.total;
} else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
t = &arg->bundle->ncp.ipcp.throughput;
#ifndef NOINET6
else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
t = &arg->bundle->ncp.ipv6cp.throughput;
#endif
else
return -1;
@ -2870,65 +2918,84 @@ RunListCommand(struct cmdargs const *arg)
static int
IfaceAddCommand(struct cmdargs const *arg)
{
int bits, n, how;
struct in_addr ifa, mask, brd;
struct ncpaddr peer, addr;
struct ncprange ifa;
struct in_addr mask;
int n, how;
if (arg->argc == arg->argn + 1) {
if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
return -1;
mask.s_addr = brd.s_addr = INADDR_BROADCAST;
ncpaddr_init(&peer);
} else {
if (arg->argc == arg->argn + 2) {
if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
return -1;
n = 1;
} else if (arg->argc == arg->argn + 3) {
if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
return -1;
if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
if (ncpaddr_family(&addr) != AF_INET)
return -1;
ncprange_sethost(&ifa, &addr);
if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
return -1;
if (!ncpaddr_getip4(&addr, &mask))
return -1;
if (!ncprange_setip4mask(&ifa, mask))
return -1;
n = 2;
} else
return -1;
if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
return -1;
if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
" differ\n");
return -1;
}
}
how = IFACE_ADD_LAST;
if (arg->cmd->args)
how |= IFACE_FORCE_ADD;
return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
}
static int
IfaceDeleteCommand(struct cmdargs const *arg)
{
struct in_addr ifa;
struct ncpaddr ifa;
struct in_addr ifa4;
int ok;
if (arg->argc != arg->argn + 1)
return -1;
if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
return -1;
if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
ncpaddr_getip4(&ifa, &ifa4) &&
arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
inet_ntoa(ifa));
ncpaddr_ntoa(&ifa));
return 1;
}
ok = iface_inDelete(arg->bundle->iface, ifa);
ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
if (!ok) {
if (arg->cmd->args)
ok = 1;
else if (arg->prompt)
prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
prompt_Printf(arg->prompt, "%s: No such interface address\n",
ncpaddr_ntoa(&ifa));
else
log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
log_Printf(LogWARN, "%s: No such interface address\n",
ncpaddr_ntoa(&ifa));
}
return !ok;
@ -2937,15 +3004,25 @@ IfaceDeleteCommand(struct cmdargs const *arg)
static int
IfaceClearCommand(struct cmdargs const *arg)
{
int how;
int family, how;
if (arg->argc != arg->argn)
family = 0;
if (arg->argc == arg->argn + 1) {
if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
family = AF_INET;
#ifndef NOINET6
else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
family = AF_INET6;
#endif
else
return -1;
} else if (arg->argc != arg->argn)
return -1;
how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
arg->bundle->phys_type.all & PHYS_AUTO ?
IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
iface_Clear(arg->bundle->iface, how);
iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
return 0;
}

View File

@ -30,6 +30,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <ctype.h>
@ -56,12 +57,16 @@
#include "physical.h"
#include "iplist.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "mp.h"
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "chat.h"
#include "auth.h"
@ -622,7 +627,7 @@ datalink_NCPUp(struct datalink *dl)
return;
} else {
dl->bundle->ncp.mp.peer = dl->peer;
ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link);
ncp_SetLink(&dl->bundle->ncp, &dl->physical->link);
auth_Select(dl->bundle, dl->peer.authname);
}

View File

@ -83,11 +83,15 @@
#include "datalink.h"
#include "slcompress.h"
#include "iplist.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "id.h"
#include "iface.h"

View File

@ -34,6 +34,7 @@
#include <netdb.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
@ -56,6 +57,8 @@
#include "ccp.h"
#include "link.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -64,115 +67,20 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
static int filter_Nam2Proto(int, char const *const *);
static int filter_Nam2Op(const char *);
static const u_int32_t netmasks[33] = {
0x00000000,
0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
};
struct in_addr
bits2mask(int bits)
{
struct in_addr result;
result.s_addr = htonl(netmasks[bits]);
return result;
}
int
ParseAddr(struct ipcp *ipcp, const char *data,
struct in_addr *paddr, struct in_addr *pmask, int *pwidth)
{
int bits, len;
char *wp;
const char *cp;
if (pmask)
pmask->s_addr = INADDR_BROADCAST; /* Assume 255.255.255.255 as default */
cp = pmask || pwidth ? strchr(data, '/') : NULL;
len = cp ? cp - data : strlen(data);
if (ipcp && strncasecmp(data, "HISADDR", len) == 0)
*paddr = ipcp->peer_ip;
else if (ipcp && strncasecmp(data, "MYADDR", len) == 0)
*paddr = ipcp->my_ip;
else if (ipcp && strncasecmp(data, "DNS0", len) == 0)
*paddr = ipcp->ns.dns[0];
else if (ipcp && strncasecmp(data, "DNS1", len) == 0)
*paddr = ipcp->ns.dns[1];
else {
char *s;
s = (char *)alloca(len + 1);
strncpy(s, data, len);
s[len] = '\0';
*paddr = GetIpAddr(s);
if (paddr->s_addr == INADDR_NONE) {
log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", s);
return 0;
}
}
if (cp && *++cp) {
bits = strtol(cp, &wp, 0);
if (cp == wp || bits < 0 || bits > 32) {
log_Printf(LogWARN, "ParseAddr: bad mask width.\n");
return 0;
}
} else if (paddr->s_addr == INADDR_ANY)
/* An IP of 0.0.0.0 without a width is anything */
bits = 0;
else
/* If a valid IP is given without a width, assume 32 bits */
bits = 32;
if (pwidth)
*pwidth = bits;
if (pmask) {
if (paddr->s_addr == INADDR_ANY)
pmask->s_addr = INADDR_ANY;
else
*pmask = bits2mask(bits);
}
return 1;
}
static int
ParsePort(const char *service, int proto)
ParsePort(const char *service, const char *proto)
{
const char *protocol_name;
char *cp;
struct servent *servent;
char *cp;
int port;
switch (proto) {
case P_IPIP:
protocol_name = "ipip";
break;
case P_UDP:
protocol_name = "udp";
break;
case P_TCP:
protocol_name = "tcp";
break;
default:
protocol_name = 0;
}
servent = getservbyname(service, protocol_name);
servent = getservbyname(service, proto);
if (servent != 0)
return ntohs(servent->s_port);
@ -189,7 +97,8 @@ ParsePort(const char *service, int proto)
* ICMP Syntax: src eq icmp_message_type
*/
static int
ParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
ParseIcmp(int argc, char const *const *argv, const struct protoent *pe,
struct filterent *tgt)
{
int type;
char *cp;
@ -197,7 +106,7 @@ ParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
switch (argc) {
case 0:
/* permit/deny all ICMP types */
tgt->f_srcop = OP_NONE;
tgt->f_srcop = tgt->f_dstop = OP_NONE;
break;
case 3:
@ -209,6 +118,7 @@ ParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
}
tgt->f_srcop = OP_EQ;
tgt->f_srcport = type;
tgt->f_dstop = OP_NONE;
}
break;
@ -223,7 +133,7 @@ ParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
* UDP Syntax: [src op port] [dst op port]
*/
static int
ParseUdpOrTcp(int argc, char const *const *argv, int proto,
ParseUdpOrTcp(int argc, char const *const *argv, const struct protoent *pe,
struct filterent *tgt)
{
tgt->f_srcop = tgt->f_dstop = OP_NONE;
@ -232,10 +142,12 @@ ParseUdpOrTcp(int argc, char const *const *argv, int proto,
if (argc >= 3 && !strcmp(*argv, "src")) {
tgt->f_srcop = filter_Nam2Op(argv[1]);
if (tgt->f_srcop == OP_NONE) {
log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n");
log_Printf(LogWARN, "ParseUdpOrTcp: bad operator\n");
return 0;
}
tgt->f_srcport = ParsePort(argv[2], proto);
if (pe == NULL)
return 0;
tgt->f_srcport = ParsePort(argv[2], pe->p_name);
if (tgt->f_srcport == 0)
return 0;
argc -= 3;
@ -245,17 +157,19 @@ ParseUdpOrTcp(int argc, char const *const *argv, int proto,
if (argc >= 3 && !strcmp(argv[0], "dst")) {
tgt->f_dstop = filter_Nam2Op(argv[1]);
if (tgt->f_dstop == OP_NONE) {
log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n");
log_Printf(LogWARN, "ParseUdpOrTcp: bad operator\n");
return 0;
}
tgt->f_dstport = ParsePort(argv[2], proto);
if (pe == NULL)
return 0;
tgt->f_dstport = ParsePort(argv[2], pe->p_name);
if (tgt->f_dstport == 0)
return 0;
argc -= 3;
argv += 3;
}
if (proto == P_TCP) {
if (pe && pe->p_proto == IPPROTO_TCP) {
for (; argc > 0; argc--, argv++)
if (!strcmp(*argv, "estab"))
tgt->f_estab = 1;
@ -276,64 +190,33 @@ ParseUdpOrTcp(int argc, char const *const *argv, int proto,
}
static int
ParseIgmp(int argc, char const * const *argv, struct filterent *tgt)
ParseGeneric(int argc, char const * const *argv, const struct protoent *pe,
struct filterent *tgt)
{
/*
* Filter currently is a catch-all. Requests are either permitted or
* dropped.
*/
if (argc != 0) {
log_Printf(LogWARN, "ParseIgmp: Too many parameters\n");
log_Printf(LogWARN, "ParseGeneric: Too many parameters\n");
return 0;
} else
tgt->f_srcop = OP_NONE;
tgt->f_srcop = tgt->f_dstop = OP_NONE;
return 1;
}
#ifdef P_GRE
static int
ParseGRE(int argc, char const * const *argv, struct filterent *tgt)
{
/*
* Filter currently is a catch-all. Requests are either permitted or
* dropped.
*/
if (argc != 0) {
log_Printf(LogWARN, "ParseGRE: Too many parameters\n");
return 0;
} else
tgt->f_srcop = OP_NONE;
return 1;
}
#endif
#ifdef P_OSPF
static int
ParseOspf(int argc, char const * const *argv, struct filterent *tgt)
{
/*
* Filter currently is a catch-all. Requests are either permitted or
* dropped.
*/
if (argc != 0) {
log_Printf(LogWARN, "ParseOspf: Too many parameters\n");
return 0;
} else
tgt->f_srcop = OP_NONE;
return 1;
}
#endif
static unsigned
addrtype(const char *addr)
{
if (!strncasecmp(addr, "MYADDR", 6) && (addr[6] == '\0' || addr[6] == '/'))
return T_MYADDR;
if (!strncasecmp(addr, "MYADDR6", 7) && (addr[7] == '\0' || addr[7] == '/'))
return T_MYADDR6;
if (!strncasecmp(addr, "HISADDR", 7) && (addr[7] == '\0' || addr[7] == '/'))
return T_HISADDR;
if (!strncasecmp(addr, "HISADDR6", 8) && (addr[8] == '\0' || addr[8] == '/'))
return T_HISADDR6;
if (!strncasecmp(addr, "DNS0", 4) && (addr[4] == '\0' || addr[4] == '/'))
return T_DNS0;
if (!strncasecmp(addr, "DNS1", 4) && (addr[4] == '\0' || addr[4] == '/'))
@ -343,7 +226,7 @@ addrtype(const char *addr)
}
static const char *
addrstr(struct in_addr addr, unsigned type)
addrstr(struct ncprange *addr, unsigned type)
{
switch (type) {
case T_MYADDR:
@ -355,30 +238,17 @@ addrstr(struct in_addr addr, unsigned type)
case T_DNS1:
return "DNS1";
}
return inet_ntoa(addr);
}
static const char *
maskstr(int bits)
{
static char str[4];
if (bits == 32)
*str = '\0';
else
snprintf(str, sizeof str, "/%d", bits);
return str;
return ncprange_ntoa(addr);
}
static int
Parse(struct ipcp *ipcp, int argc, char const *const *argv,
struct filterent *ofp)
filter_Parse(struct ncp *ncp, int argc, char const *const *argv,
struct filterent *ofp)
{
int action, proto;
int val, ruleno;
struct filterent fe;
struct protoent *pe;
char *wp;
struct filterent filterdata;
int action, family, ruleno, val, width;
ruleno = strtol(*argv, &wp, 0);
if (*argv == wp || ruleno >= MAXFILTERS) {
@ -401,8 +271,7 @@ Parse(struct ipcp *ipcp, int argc, char const *const *argv,
}
argv++;
proto = P_NONE;
memset(&filterdata, '\0', sizeof filterdata);
memset(&fe, '\0', sizeof fe);
val = strtol(*argv, &wp, 0);
if (!*wp && val >= 0 && val < MAXFILTERS) {
@ -420,56 +289,71 @@ Parse(struct ipcp *ipcp, int argc, char const *const *argv,
ofp->f_action = A_NONE;
return 1;
} else {
log_Printf(LogWARN, "Parse: bad action: %s\n", *argv);
log_Printf(LogWARN, "Parse: %s: bad action\n", *argv);
return 0;
}
filterdata.f_action = action;
fe.f_action = action;
argc--;
argv++;
if (argc && argv[0][0] == '!' && !argv[0][1]) {
filterdata.f_invert = 1;
fe.f_invert = 1;
argc--;
argv++;
}
proto = filter_Nam2Proto(argc, argv);
if (proto == P_NONE) {
if (!argc)
log_Printf(LogWARN, "Parse: address/mask is expected.\n");
else if (ParseAddr(ipcp, *argv, &filterdata.f_src.ipaddr,
&filterdata.f_src.mask, &filterdata.f_src.width)) {
filterdata.f_srctype = addrtype(*argv);
ncprange_init(&fe.f_src);
ncprange_init(&fe.f_dst);
if (argc == 0)
pe = NULL;
else if ((pe = getprotobyname(*argv)) == NULL && strcmp(*argv, "all") != 0) {
if (argc < 2) {
log_Printf(LogWARN, "Parse: Protocol or address pair expected\n");
return 0;
} else if (strcasecmp(*argv, "any") == 0 ||
ncprange_aton(&fe.f_src, ncp, *argv)) {
family = ncprange_family(&fe.f_src);
if (!ncprange_getwidth(&fe.f_src, &width))
width = 0;
if (width == 0)
ncprange_init(&fe.f_src);
fe.f_srctype = addrtype(*argv);
argc--;
argv++;
proto = filter_Nam2Proto(argc, argv);
if (!argc)
log_Printf(LogWARN, "Parse: address/mask is expected.\n");
else if (proto == P_NONE) {
if (ParseAddr(ipcp, *argv, &filterdata.f_dst.ipaddr,
&filterdata.f_dst.mask, &filterdata.f_dst.width)) {
filterdata.f_dsttype = addrtype(*argv);
argc--;
argv++;
} else
filterdata.f_dsttype = T_ADDR;
if (argc) {
proto = filter_Nam2Proto(argc, argv);
if (proto == P_NONE) {
log_Printf(LogWARN, "Parse: %s: Invalid protocol\n", *argv);
return 0;
} else {
argc--;
argv++;
}
}
if (strcasecmp(*argv, "any") == 0 ||
ncprange_aton(&fe.f_dst, ncp, *argv)) {
if (ncprange_family(&fe.f_dst) != AF_UNSPEC &&
ncprange_family(&fe.f_src) != AF_UNSPEC &&
family != ncprange_family(&fe.f_dst)) {
log_Printf(LogWARN, "Parse: src and dst address families differ\n");
return 0;
}
if (!ncprange_getwidth(&fe.f_dst, &width))
width = 0;
if (width == 0)
ncprange_init(&fe.f_dst);
fe.f_dsttype = addrtype(*argv);
argc--;
argv++;
} else {
argc--;
argv++;
log_Printf(LogWARN, "Parse: Protocol or address pair expected\n");
return 0;
}
if (argc) {
if ((pe = getprotobyname(*argv)) == NULL && strcmp(*argv, "all") != 0) {
log_Printf(LogWARN, "Parse: %s: Protocol expected\n", *argv);
return 0;
} else {
argc--;
argv++;
}
}
} else {
log_Printf(LogWARN, "Parse: Address/protocol expected.\n");
log_Printf(LogWARN, "Parse: Protocol or address pair expected\n");
return 0;
}
} else {
@ -477,60 +361,49 @@ Parse(struct ipcp *ipcp, int argc, char const *const *argv,
argv++;
}
if (argc >= 2 && strcmp(argv[argc - 2], "timeout") == 0) {
filterdata.timeout = strtoul(argv[argc - 1], NULL, 10);
if (argc >= 2 && strcmp(*argv, "timeout") == 0) {
fe.timeout = strtoul(argv[1], NULL, 10);
argc -= 2;
argv += 2;
}
val = 1;
filterdata.f_proto = proto;
fe.f_proto = (pe == NULL) ? 0 : pe->p_proto;
switch (proto) {
case P_TCP:
val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata);
break;
case P_UDP:
val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata);
break;
case P_IPIP:
val = ParseUdpOrTcp(argc, argv, P_IPIP, &filterdata);
break;
case P_ICMP:
val = ParseIcmp(argc, argv, &filterdata);
break;
case P_IGMP:
val = ParseIgmp(argc, argv, &filterdata);
break;
#ifdef P_OSPF
case P_OSPF:
val = ParseOspf(argc, argv, &filterdata);
break;
switch (fe.f_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_IPIP:
#ifndef NOINET6
case IPPROTO_IPV6:
#endif
#ifdef P_GRE
case P_GRE:
val = ParseGRE(argc, argv, &filterdata);
val = ParseUdpOrTcp(argc, argv, pe, &fe);
break;
case IPPROTO_ICMP:
#ifndef NOINET6
case IPPROTO_ICMPV6:
#endif
val = ParseIcmp(argc, argv, pe, &fe);
break;
default:
val = ParseGeneric(argc, argv, pe, &fe);
break;
}
log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.f_src.ipaddr));
log_Printf(LogDEBUG, "Parse: Src mask: %s\n",
inet_ntoa(filterdata.f_src.mask));
log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.f_dst.ipaddr));
log_Printf(LogDEBUG, "Parse: Dst mask: %s\n",
inet_ntoa(filterdata.f_dst.mask));
log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto);
log_Printf(LogDEBUG, "Parse: Src: %s\n", ncprange_ntoa(&fe.f_src));
log_Printf(LogDEBUG, "Parse: Dst: %s\n", ncprange_ntoa(&fe.f_dst));
log_Printf(LogDEBUG, "Parse: Proto: %d\n", fe.f_proto);
log_Printf(LogDEBUG, "Parse: src: %s (%d)\n",
filter_Op2Nam(filterdata.f_srcop), filterdata.f_srcport);
filter_Op2Nam(fe.f_srcop), fe.f_srcport);
log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n",
filter_Op2Nam(filterdata.f_dstop), filterdata.f_dstport);
log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.f_estab);
log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.f_syn);
log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.f_finrst);
filter_Op2Nam(fe.f_dstop), fe.f_dstport);
log_Printf(LogDEBUG, "Parse: estab: %u\n", fe.f_estab);
log_Printf(LogDEBUG, "Parse: syn: %u\n", fe.f_syn);
log_Printf(LogDEBUG, "Parse: finrst: %u\n", fe.f_finrst);
if (val)
*ofp = filterdata;
*ofp = fe;
return val;
}
@ -557,7 +430,7 @@ filter_Set(struct cmdargs const *arg)
return -1;
}
Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1,
filter_Parse(&arg->bundle->ncp, arg->argc - arg->argn - 1,
arg->argv + arg->argn + 1, filter->rule);
return 0;
}
@ -580,18 +453,29 @@ filter_Action2Nam(int act)
static void
doShowFilter(struct filterent *fp, struct prompt *prompt)
{
struct protoent *pe;
int n;
for (n = 0; n < MAXFILTERS; n++, fp++) {
if (fp->f_action != A_NONE) {
prompt_Printf(prompt, " %2d %s", n, filter_Action2Nam(fp->f_action));
prompt_Printf(prompt, "%c ", fp->f_invert ? '!' : ' ');
prompt_Printf(prompt, "%s%s ", addrstr(fp->f_src.ipaddr, fp->f_srctype),
maskstr(fp->f_src.width));
prompt_Printf(prompt, "%s%s ", addrstr(fp->f_dst.ipaddr, fp->f_dsttype),
maskstr(fp->f_dst.width));
if (ncprange_isset(&fp->f_src))
prompt_Printf(prompt, "%s ", addrstr(&fp->f_src, fp->f_srctype));
else
prompt_Printf(prompt, "any ");
if (ncprange_isset(&fp->f_dst))
prompt_Printf(prompt, "%s ", addrstr(&fp->f_dst, fp->f_dsttype));
else
prompt_Printf(prompt, "any ");
if (fp->f_proto) {
prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->f_proto));
if ((pe = getprotobynumber(fp->f_proto)) == NULL)
prompt_Printf(prompt, "P:%d", fp->f_proto);
else
prompt_Printf(prompt, "%s", pe->p_name);
if (fp->f_srcop)
prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->f_srcop),
@ -605,7 +489,8 @@ doShowFilter(struct filterent *fp, struct prompt *prompt)
prompt_Printf(prompt, " syn");
if (fp->f_finrst)
prompt_Printf(prompt, " finrst");
}
} else
prompt_Printf(prompt, "all");
if (fp->timeout != 0)
prompt_Printf(prompt, " timeout %u", fp->timeout);
prompt_Printf(prompt, "\n");
@ -652,33 +537,6 @@ filter_Show(struct cmdargs const *arg)
return 0;
}
static const char * const protoname[] = {
"none", "tcp", "udp", "icmp", "ospf", "igmp", "gre", "ipip"
};
const char *
filter_Proto2Nam(int proto)
{
if (proto >= sizeof protoname / sizeof protoname[0])
return "unknown";
return protoname[proto];
}
static int
filter_Nam2Proto(int argc, char const *const *argv)
{
int proto;
if (argc == 0)
proto = 0;
else
for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--)
if (!strcasecmp(*argv, protoname[proto]))
break;
return proto;
}
static const char * const opname[] = {"none", "eq", "gt", "lt"};
const char *
@ -703,35 +561,47 @@ filter_Nam2Op(const char *cp)
}
void
filter_AdjustAddr(struct filter *filter, struct in_addr *my_ip,
struct in_addr *peer_ip, struct in_addr dns[2])
filter_AdjustAddr(struct filter *filter, struct ncpaddr *local,
struct ncpaddr *remote, struct in_addr *dns)
{
struct filterent *fp;
int n;
for (fp = filter->rule, n = 0; n < MAXFILTERS; fp++, n++)
if (fp->f_action != A_NONE) {
if (my_ip) {
if (fp->f_srctype == T_MYADDR)
fp->f_src.ipaddr = *my_ip;
if (fp->f_dsttype == T_MYADDR)
fp->f_dst.ipaddr = *my_ip;
if (local) {
if (fp->f_srctype == T_MYADDR && ncpaddr_family(local) == AF_INET)
ncprange_sethost(&fp->f_src, local);
if (fp->f_dsttype == T_MYADDR && ncpaddr_family(local) == AF_INET)
ncprange_sethost(&fp->f_dst, local);
#ifndef NOINET6
if (fp->f_srctype == T_MYADDR6 && ncpaddr_family(local) == AF_INET6)
ncprange_sethost(&fp->f_src, local);
if (fp->f_dsttype == T_MYADDR6 && ncpaddr_family(local) == AF_INET6)
ncprange_sethost(&fp->f_dst, local);
#endif
}
if (peer_ip) {
if (fp->f_srctype == T_HISADDR)
fp->f_src.ipaddr = *peer_ip;
if (fp->f_dsttype == T_HISADDR)
fp->f_dst.ipaddr = *peer_ip;
if (remote) {
if (fp->f_srctype == T_HISADDR && ncpaddr_family(remote) == AF_INET)
ncprange_sethost(&fp->f_src, remote);
if (fp->f_dsttype == T_HISADDR && ncpaddr_family(remote) == AF_INET)
ncprange_sethost(&fp->f_dst, remote);
#ifndef NOINET6
if (fp->f_srctype == T_HISADDR6 && ncpaddr_family(remote) == AF_INET6)
ncprange_sethost(&fp->f_src, remote);
if (fp->f_dsttype == T_HISADDR6 && ncpaddr_family(remote) == AF_INET6)
ncprange_sethost(&fp->f_dst, remote);
#endif
}
if (dns) {
if (fp->f_srctype == T_DNS0)
fp->f_src.ipaddr = dns[0];
ncprange_setip4host(&fp->f_src, dns[0]);
if (fp->f_dsttype == T_DNS0)
fp->f_dst.ipaddr = dns[0];
ncprange_setip4host(&fp->f_dst, dns[0]);
if (fp->f_srctype == T_DNS1)
fp->f_src.ipaddr = dns[1];
ncprange_setip4host(&fp->f_src, dns[1]);
if (fp->f_dsttype == T_DNS1)
fp->f_dst.ipaddr = dns[1];
ncprange_setip4host(&fp->f_dst, dns[1]);
}
}
}

View File

@ -28,22 +28,6 @@
* $FreeBSD$
*/
/* Known protocols - f_proto */
#define P_NONE 0
#define P_TCP 1
#define P_UDP 2
#define P_ICMP 3
#ifdef IPPROTO_OSPFIGP
#define P_OSPF 4
#endif
#define P_IGMP 5
#ifdef IPPROTO_GRE
#define P_GRE 6
#endif
#define P_ESP 7
#define P_AH 8
#define P_IPIP 9
/* Operations - f_srcop, f_dstop */
#define OP_NONE 0
#define OP_EQ 1
@ -53,9 +37,11 @@
/* srctype or dsttype */
#define T_ADDR 0
#define T_MYADDR 1
#define T_HISADDR 2
#define T_DNS0 3
#define T_DNS1 4
#define T_MYADDR6 2
#define T_HISADDR 3
#define T_HISADDR6 4
#define T_DNS0 5
#define T_DNS1 6
/*
* There's a struct filterent for each possible filter rule. The
@ -63,17 +49,12 @@
* them) - which is also conveniently a power of 2 (32 bytes) on
* architectures where sizeof(int)==4 (this makes indexing faster).
*
* f_action and f_proto only need to be 6 and 3 bits, respectively,
* but making them 8 bits allows them to be efficently accessed using
* byte operations as well as allowing space for future expansion
* (expanding MAXFILTERS or converting f_proto IPPROTO_... values).
*
* Note that there are four free bits in the initial word for future
* extensions.
*/
struct filterent {
unsigned f_action : 8; /* Filtering action: goto or A_... */
unsigned f_proto : 8; /* Protocol: P_... */
int f_proto; /* Protocol: getprotoby*() */
unsigned f_action : 8; /* Filtering action: goto or A_... */
unsigned f_srcop : 2; /* Source port operation: OP_... */
unsigned f_dstop : 2; /* Destination port operation: OP_... */
unsigned f_srctype : 3; /* T_ value of src */
@ -82,8 +63,8 @@ struct filterent {
unsigned f_syn : 1; /* Check TCP SYN bit */
unsigned f_finrst : 1; /* Check TCP FIN/RST bits */
unsigned f_invert : 1; /* true to complement match */
struct in_range f_src; /* Source address and mask */
struct in_range f_dst; /* Destination address and mask */
struct ncprange f_src; /* Source address and mask */
struct ncprange f_dst; /* Destination address and mask */
u_short f_srcport; /* Source port, compared with f_srcop */
u_short f_dstport; /* Destination port, compared with f_dstop */
unsigned timeout; /* Keep alive value for passed packet */
@ -112,13 +93,9 @@ struct filter {
struct ipcp;
struct cmdargs;
extern int ParseAddr(struct ipcp *, const char *, struct in_addr *,
struct in_addr *, int *);
extern int filter_Show(struct cmdargs const *);
extern int filter_Set(struct cmdargs const *);
extern const char * filter_Action2Nam(int);
extern const char *filter_Proto2Nam(int);
extern const char *filter_Op2Nam(int);
extern struct in_addr bits2mask(int);
extern void filter_AdjustAddr(struct filter *, struct in_addr *,
struct in_addr *, struct in_addr [2]);
extern void filter_AdjustAddr(struct filter *, struct ncpaddr *,
struct ncpaddr *, struct in_addr *);

View File

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
@ -49,6 +50,8 @@
#include "hdlc.h"
#include "throughput.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -59,6 +62,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "async.h"
#include "physical.h"
@ -508,7 +513,6 @@ FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
return;
case ST_OPENED:
(*fp->fn->LayerDown)(fp);
(*fp->parent->LayerDown)(fp->parent->object, fp);
break;
}
@ -559,6 +563,7 @@ FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
NewState(fp, ST_ACKSENT);
else
NewState(fp, ST_REQSENT);
(*fp->parent->LayerDown)(fp->parent->object, fp);
break;
case ST_REQSENT:
if (ackaction)
@ -889,6 +894,15 @@ FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp)
fsm_Close(&fp->bundle->ncp.ipcp.fsm);
}
break;
#ifndef NOINET6
case PROTO_IPV6CP:
if (fp->proto == PROTO_LCP) {
log_Printf(LogPHASE, "%s: IPV6CP protocol reject closes IPV6CP !\n",
fp->link->name);
fsm_Close(&fp->bundle->ncp.ipv6cp.fsm);
}
break;
#endif
case PROTO_MP:
if (fp->proto == PROTO_LCP) {
struct lcp *lcp = fsm2lcp(fp);

View File

@ -209,6 +209,7 @@ static struct {
{ 0x0051, 0x0051, "KNX Bridging Data" },
{ 0x0053, 0x0053, "Encryption" },
{ 0x0055, 0x0055, "Individual Link Encryption" },
{ 0x0057, 0x0057, "Internet Protocol V6" },
{ 0x006f, 0x006f, "Stampede Bridging" },
{ 0x0071, 0x0071, "BAP Bandwidth Allocation Protocol" },
{ 0x0073, 0x0073, "MP+ Protocol" },
@ -259,6 +260,7 @@ static struct {
{ 0x8051, 0x8051, "KNX Bridging Control Protocol" },
{ 0x8053, 0x8053, "Encryption Control Protocol" },
{ 0x8055, 0x8055, "Individual Link Encryption Control Protocol" },
{ 0x8057, 0x8057, "Internet Protocol V6 Control Protocol" },
{ 0x806f, 0x806f, "Stampede Bridging Control Protocol" },
{ 0x8073, 0x8073, "MP+ Control Protocol" },
{ 0x8071, 0x8071, "BACP Bandwidth Allocation Control Protocol" },

View File

@ -31,10 +31,15 @@
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_var.h>
#include <net/route.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#ifndef NOINET6
#include <netinet6/nd6.h>
#endif
#include <sys/un.h>
#include <errno.h>
@ -60,6 +65,8 @@
#include "throughput.h"
#include "slcompress.h"
#include "descriptor.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "lcp.h"
@ -69,32 +76,17 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "prompt.h"
#include "iface.h"
static int
bitsinmask(struct in_addr mask)
{
u_int32_t bitmask, maskaddr;
int bits;
bitmask = 0xffffffff;
maskaddr = ntohl(mask.s_addr);
for (bits = 32; bits >= 0; bits--) {
if (maskaddr == bitmask)
break;
bitmask &= ~(1 << (32 - bits));
}
return bits;
}
struct iface *
iface_Create(const char *name)
{
int mib[6], s, maxtries, err;
int mib[6], maxtries, err;
size_t needed, namelen;
char *buf, *ptr, *end;
struct if_msghdr *ifm;
@ -104,12 +96,6 @@ iface_Create(const char *name)
struct iface *iface;
struct iface_addr *addr;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
fprintf(stderr, "iface_Create: socket(): %s\n", strerror(errno));
return NULL;
}
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
@ -122,20 +108,17 @@ iface_Create(const char *name)
do {
if (maxtries-- == 0 || (err && err != ENOMEM)) {
fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
close(s);
return NULL;
}
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
strerror(errno));
close(s);
return NULL;
}
if ((buf = (char *)malloc(needed)) == NULL) {
fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
close(s);
return NULL;
}
@ -166,8 +149,8 @@ iface_Create(const char *name)
iface->index = ifm->ifm_index;
iface->flags = ifm->ifm_flags;
iface->mtu = 0;
iface->in_addrs = 0;
iface->in_addr = NULL;
iface->addrs = 0;
iface->addr = NULL;
}
ptr += ifm->ifm_msglen; /* First ifa_msghdr */
for (; ptr < end; ptr += ifam->ifam_msglen) {
@ -180,255 +163,350 @@ iface_Create(const char *name)
/* Found a configured interface ! */
iface_ParseHdr(ifam, sa);
if (sa[RTAX_IFA] && sa[RTAX_IFA]->sa_family == AF_INET) {
if (sa[RTAX_IFA] && (sa[RTAX_IFA]->sa_family == AF_INET
#ifndef NOINET6
|| sa[RTAX_IFA]->sa_family == AF_INET6
#endif
)) {
/* Record the address */
addr = (struct iface_addr *)realloc
(iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
addr = (struct iface_addr *)
realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
if (addr == NULL)
break;
iface->in_addr = addr;
iface->addr = addr;
addr += iface->in_addrs;
iface->in_addrs++;
addr->ifa = ((struct sockaddr_in *)sa[RTAX_IFA])->sin_addr;
addr += iface->addrs;
iface->addrs++;
ncprange_setsa(&addr->ifa, sa[RTAX_IFA], sa[RTAX_NETMASK]);
if (sa[RTAX_BRD])
addr->brd = ((struct sockaddr_in *)sa[RTAX_BRD])->sin_addr;
ncpaddr_setsa(&addr->peer, sa[RTAX_BRD]);
else
addr->brd.s_addr = INADDR_ANY;
if (sa[RTAX_NETMASK])
addr->mask = ((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr;
else
addr->mask.s_addr = INADDR_ANY;
addr->bits = bitsinmask(addr->mask);
ncpaddr_init(&addr->peer);
}
}
}
}
free(buf);
close(s);
return iface;
}
static void
iface_addr_Zap(const char *name, struct iface_addr *addr)
static int
iface_addr_Zap(const char *name, struct iface_addr *addr, int s)
{
struct ifaliasreq ifra;
struct sockaddr_in *me, *peer;
int s;
#ifndef NOINET6
struct in6_aliasreq ifra6;
#endif
struct sockaddr_in *me4, *msk4, *peer4;
struct sockaddr_storage ssme, sspeer, ssmsk;
int res;
s = ID0socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
log_Printf(LogERROR, "iface_addr_Zap: socket(): %s\n", strerror(errno));
else {
ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
ncpaddr_getsa(&addr->peer, &sspeer);
res = 0;
switch (ncprange_family(&addr->ifa)) {
case AF_INET:
memset(&ifra, '\0', sizeof ifra);
strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
me = (struct sockaddr_in *)&ifra.ifra_addr;
peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
me->sin_family = peer->sin_family = AF_INET;
me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
me->sin_addr = addr->ifa;
peer->sin_addr = addr->brd;
log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(addr->ifa));
if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
log_Printf(LogWARN, "iface_addr_Zap: ioctl(SIOCDIFADDR, %s): %s\n",
inet_ntoa(addr->ifa), strerror(errno));
close(s);
me4 = (struct sockaddr_in *)&ifra.ifra_addr;
memcpy(me4, &ssme, sizeof *me4);
msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
memcpy(msk4, &ssmsk, sizeof *msk4);
peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
peer4->sin_family = AF_INET;
peer4->sin_len = sizeof(*peer4);
peer4->sin_addr.s_addr = INADDR_NONE;
} else
memcpy(peer4, &sspeer, sizeof *peer4);
res = ID0ioctl(s, SIOCDIFADDR, &ifra);
break;
#ifndef NOINET6
case AF_INET6:
memset(&ifra6, '\0', sizeof ifra6);
strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
ifra6.ifra_prefixmask.sin6_family = AF_UNSPEC;
if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
else
memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
res = ID0ioctl(s, SIOCDIFADDR_IN6, &ifra6);
break;
#endif
}
if (res == -1) {
char dst[40];
const char *end =
#ifndef NOINET6
ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
#endif
"";
if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
end, ncprange_ntoa(&addr->ifa), strerror(errno));
else {
snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
}
}
return res != -1;
}
static void
iface_addr_Add(const char *name, struct iface_addr *addr, int s)
{
struct ifaliasreq ifra;
#ifndef NOINET6
struct in6_aliasreq ifra6;
#endif
struct sockaddr_in *me4, *msk4, *peer4;
struct sockaddr_storage ssme, sspeer, ssmsk;
int res;
ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
ncpaddr_getsa(&addr->peer, &sspeer);
res = 0;
switch (ncprange_family(&addr->ifa)) {
case AF_INET:
memset(&ifra, '\0', sizeof ifra);
strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
me4 = (struct sockaddr_in *)&ifra.ifra_addr;
memcpy(me4, &ssme, sizeof *me4);
msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
memcpy(msk4, &ssmsk, sizeof *msk4);
peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
peer4->sin_family = AF_INET;
peer4->sin_len = sizeof(*peer4);
peer4->sin_addr.s_addr = INADDR_NONE;
} else
memcpy(peer4, &sspeer, sizeof *peer4);
res = ID0ioctl(s, SIOCAIFADDR, &ifra);
break;
#ifndef NOINET6
case AF_INET6:
memset(&ifra6, '\0', sizeof ifra6);
strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
else
memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6);
break;
#endif
}
if (res == -1) {
char dst[40];
const char *end =
#ifndef NOINET6
ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
#endif
"";
if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
end, ncprange_ntoa(&addr->ifa), strerror(errno));
else {
snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
log_Printf(LogWARN, "iface add: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
}
}
}
void
iface_inClear(struct iface *iface, int how)
iface_Clear(struct iface *iface, struct ncp *ncp, int family, int how)
{
int n, addrs;
int addrs, af, inskip, in6skip, n, s4 = -1, s6 = -1, *s;
if (iface->in_addrs) {
addrs = n = how == IFACE_CLEAR_ALL ? 0 : 1;
for (; n < iface->in_addrs; n++)
iface_addr_Zap(iface->name, iface->in_addr + n);
if (iface->addrs) {
inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1;
addrs = 0;
for (n = 0; n < iface->addrs; n++) {
af = ncprange_family(&iface->addr[n].ifa);
if (family == 0 || family == af) {
if (!iface->addr[n].system && (how & IFACE_SYSTEM))
continue;
switch (af) {
case AF_INET:
if (inskip) {
inskip = 0;
continue;
}
s = &s4;
break;
#ifndef NOINET6
case AF_INET6:
if (in6skip) {
in6skip = 0;
continue;
}
s = &s6;
break;
#endif
}
if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1)
log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno));
else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) {
ncp_IfaceAddrDeleted(ncp, iface->addr + n);
bcopy(iface->addr + n + 1, iface->addr + n,
(iface->addrs - n - 1) * sizeof *iface->addr);
iface->addrs--;
n--;
}
}
}
iface->in_addrs = addrs;
/* Don't bother realloc()ing - we have little to gain */
if (s4)
close(s4);
if (s6)
close(s6);
}
}
int
iface_inAdd(struct iface *iface, struct in_addr ifa, struct in_addr mask,
struct in_addr brd, int how)
iface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa,
const struct ncpaddr *peer, int how)
{
int slot, s, chg, nochange;
struct ifaliasreq ifra;
struct sockaddr_in *me, *peer, *msk;
int af, n, s, width;
struct ncpaddr ifaddr, ncplocal;
struct iface_addr *addr;
for (slot = 0; slot < iface->in_addrs; slot++)
if (iface->in_addr[slot].ifa.s_addr == ifa.s_addr) {
if (how & IFACE_FORCE_ADD)
break;
else
/* errno = EEXIST; */
return 0;
}
addr = (struct iface_addr *)realloc
(iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
if (addr == NULL) {
log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
af = ncprange_family(ifa);
if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) {
log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno));
return 0;
}
iface->in_addr = addr;
ncprange_getaddr(ifa, &ncplocal);
/*
* We've gotta be careful here. If we try to add an address with the
* same destination as an existing interface, nothing will work.
* Instead, we tweak all previous address entries that match the
* to-be-added destination to 255.255.255.255 (w/ a similar netmask).
* There *may* be more than one - if the user has ``iface add''ed
* stuff previously.
*/
nochange = 0;
s = -1;
for (chg = 0; chg < iface->in_addrs; chg++) {
if ((iface->in_addr[chg].brd.s_addr == brd.s_addr &&
brd.s_addr != INADDR_BROADCAST) || chg == slot) {
/*
* If we've found an entry that exactly matches what we want to add,
* don't remove it and then add it again. If we do, it's possible
* that the kernel will (correctly) ``tidy up'' any routes that use
* the IP number as a destination.
*/
if (chg == slot && iface->in_addr[chg].mask.s_addr == mask.s_addr) {
if (brd.s_addr == iface->in_addr[slot].brd.s_addr)
nochange = 1;
/*
* If only the destination address has changed, the SIOCAIFADDR
* we do after the current loop will change it.
*/
continue;
}
if (s == -1 && (s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
return 0;
for (n = 0; n < iface->addrs; n++) {
if (ncprange_contains(&iface->addr[n].ifa, &ncplocal)) {
if (!(how & IFACE_FORCE_ADD)) {
close(s);
return 0; /* errno = EEXIST; */
}
memset(&ifra, '\0', sizeof ifra);
strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
me = (struct sockaddr_in *)&ifra.ifra_addr;
msk = (struct sockaddr_in *)&ifra.ifra_mask;
peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
me->sin_addr = iface->in_addr[chg].ifa;
msk->sin_addr = iface->in_addr[chg].mask;
peer->sin_addr = iface->in_addr[chg].brd;
log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(me->sin_addr));
ID0ioctl(s, SIOCDIFADDR, &ifra); /* Don't care if it fails... */
if (chg != slot) {
peer->sin_addr.s_addr = iface->in_addr[chg].brd.s_addr =
msk->sin_addr.s_addr = iface->in_addr[chg].mask.s_addr =
INADDR_BROADCAST;
iface->in_addr[chg].bits = 32;
log_Printf(LogDEBUG, "Add %s -> 255.255.255.255\n",
inet_ntoa(me->sin_addr));
if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && errno != EEXIST) {
/* Oops - that's bad(ish) news ! We've lost an alias ! */
log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
inet_ntoa(me->sin_addr), strerror(errno));
iface->in_addrs--;
bcopy(iface->in_addr + chg + 1, iface->in_addr + chg,
(iface->in_addrs - chg) * sizeof iface->in_addr[0]);
if (slot > chg)
slot--;
chg--;
}
if (ncprange_equal(&iface->addr[n].ifa, ifa) &&
ncpaddr_equal(&iface->addr[n].peer, peer)) {
close(s);
return 1; /* Already there */
}
width =
#ifndef NOINET6
(af == AF_INET6) ? 128 :
#endif
32;
iface_addr_Zap(iface->name, iface->addr + n, s);
ncprange_setwidth(&iface->addr[n].ifa, width);
ncprange_getaddr(&iface->addr[n].ifa, &ifaddr);
if (ncpaddr_equal(&ifaddr, &ncplocal))
ncpaddr_copy(&iface->addr[n].peer, peer);
else
ncpaddr_init(&iface->addr[n].peer);
iface_addr_Add(iface->name, iface->addr + n, s);
if (ncpaddr_equal(&ifaddr, &ncplocal)) {
close(s);
ncp_IfaceAddrAdded(ncp, iface->addr + n);
return 1;
}
}
}
if (!nochange) {
if (s == -1 && (s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
return 0;
}
memset(&ifra, '\0', sizeof ifra);
strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
me = (struct sockaddr_in *)&ifra.ifra_addr;
msk = (struct sockaddr_in *)&ifra.ifra_mask;
peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
me->sin_addr = ifa;
msk->sin_addr = mask;
peer->sin_addr = brd;
if (log_IsKept(LogDEBUG)) {
char buf[16];
strncpy(buf, inet_ntoa(brd), sizeof buf-1);
buf[sizeof buf - 1] = '\0';
log_Printf(LogDEBUG, "Add %s -> %s\n", inet_ntoa(ifa), buf);
}
/* An EEXIST failure w/ brd == INADDR_BROADCAST is ok (and works!) */
if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 &&
(brd.s_addr != INADDR_BROADCAST || errno != EEXIST)) {
log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
inet_ntoa(ifa), strerror(errno));
ID0ioctl(s, SIOCDIFADDR, &ifra); /* EEXIST ? */
close(s);
return 0;
}
}
if (s != -1)
addr = (struct iface_addr *)realloc
(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
if (addr == NULL) {
log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
close(s);
if (slot == iface->in_addrs) {
/* We're adding a new interface address */
if (how & IFACE_ADD_FIRST) {
/* Stuff it at the start of our list */
slot = 0;
bcopy(iface->in_addr, iface->in_addr + 1,
iface->in_addrs * sizeof iface->in_addr[0]);
}
iface->in_addrs++;
} else if (how & IFACE_ADD_FIRST) {
/* Shift it up to the first slot */
bcopy(iface->in_addr, iface->in_addr + 1, slot * sizeof iface->in_addr[0]);
slot = 0;
return 0;
}
iface->addr = addr;
iface->in_addr[slot].ifa = ifa;
iface->in_addr[slot].mask = mask;
iface->in_addr[slot].brd = brd;
iface->in_addr[slot].bits = bitsinmask(iface->in_addr[slot].mask);
if (how & IFACE_ADD_FIRST) {
/* Stuff it at the start of our list */
n = 0;
bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr);
} else
n = iface->addrs;
iface->addrs++;
ncprange_copy(&iface->addr[n].ifa, ifa);
ncpaddr_copy(&iface->addr[n].peer, peer);
iface->addr[n].system = !!(how & IFACE_SYSTEM);
iface_addr_Add(iface->name, iface->addr + n, s);
close(s);
ncp_IfaceAddrAdded(ncp, iface->addr + n);
return 1;
}
int
iface_inDelete(struct iface *iface, struct in_addr ip)
iface_Delete(struct iface *iface, struct ncp *ncp, const struct ncpaddr *del)
{
int n;
struct ncpaddr found;
int n, res, s;
for (n = 0; n < iface->in_addrs; n++)
if (iface->in_addr[n].ifa.s_addr == ip.s_addr) {
iface_addr_Zap(iface->name, iface->in_addr + n);
bcopy(iface->in_addr + n + 1, iface->in_addr + n,
(iface->in_addrs - n - 1) * sizeof iface->in_addr[0]);
iface->in_addrs--;
return 1;
if ((s = ID0socket(ncpaddr_family(del), SOCK_DGRAM, 0)) == -1) {
log_Printf(LogERROR, "iface_Delete: socket(): %s\n", strerror(errno));
return 0;
}
for (n = res = 0; n < iface->addrs; n++) {
ncprange_getaddr(&iface->addr[n].ifa, &found);
if (ncpaddr_equal(&found, del)) {
iface_addr_Zap(iface->name, iface->addr + n, s);
ncp_IfaceAddrDeleted(ncp, iface->addr + n);
bcopy(iface->addr + n + 1, iface->addr + n,
(iface->addrs - n - 1) * sizeof *iface->addr);
iface->addrs--;
res = 1;
break;
}
}
return 0;
close(s);
return res;
}
#define IFACE_ADDFLAGS 1
@ -495,7 +573,7 @@ iface_Destroy(struct iface *iface)
if (iface != NULL) {
free(iface->name);
free(iface->in_addr);
free(iface->addr);
free(iface);
}
}
@ -527,8 +605,13 @@ struct {
int
iface_Show(struct cmdargs const *arg)
{
struct ncpaddr ncpaddr;
struct iface *iface = arg->bundle->iface, *current;
int f, flags;
#ifndef NOINET6
int scopeid, width;
#endif
struct in_addr mask;
current = iface_Create(iface->name);
flags = iface->flags = current->flags;
@ -542,20 +625,34 @@ iface_Show(struct cmdargs const *arg)
flags &= ~if_flags[f].flag;
}
prompt_Printf(arg->prompt, "> mtu %d has %d address%s:\n", iface->mtu,
iface->in_addrs, iface->in_addrs == 1 ? "" : "es");
iface->addrs, iface->addrs == 1 ? "" : "es");
for (f = 0; f < iface->in_addrs; f++) {
prompt_Printf(arg->prompt, " %s", inet_ntoa(iface->in_addr[f].ifa));
if (iface->in_addr[f].bits >= 0)
prompt_Printf(arg->prompt, "/%d", iface->in_addr[f].bits);
if (iface->flags & IFF_POINTOPOINT)
prompt_Printf(arg->prompt, " -> %s", inet_ntoa(iface->in_addr[f].brd));
else if (iface->flags & IFF_BROADCAST)
prompt_Printf(arg->prompt, " broadcast %s",
inet_ntoa(iface->in_addr[f].brd));
if (iface->in_addr[f].bits < 0)
prompt_Printf(arg->prompt, " (mask %s)",
inet_ntoa(iface->in_addr[f].mask));
for (f = 0; f < iface->addrs; f++) {
ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr);
switch (ncprange_family(&iface->addr[f].ifa)) {
case AF_INET:
prompt_Printf(arg->prompt, " inet %s --> ", ncpaddr_ntoa(&ncpaddr));
if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
prompt_Printf(arg->prompt, "255.255.255.255");
else
prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer));
ncprange_getip4mask(&iface->addr[f].ifa, &mask);
prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr));
break;
#ifndef NOINET6
case AF_INET6:
prompt_Printf(arg->prompt, " inet6 %s", ncpaddr_ntoa(&ncpaddr));
if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC)
prompt_Printf(arg->prompt, " --> %s",
ncpaddr_ntoa(&iface->addr[f].peer));
ncprange_getwidth(&iface->addr[f].ifa, &width);
prompt_Printf(arg->prompt, " prefixlen %d", width);
if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1)
prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid);
break;
#endif
}
prompt_Printf(arg->prompt, "\n");
}

View File

@ -29,10 +29,9 @@
struct ifa_msghdr;
struct iface_addr {
struct in_addr ifa; /* local address */
struct in_addr mask; /* netmask */
int bits; /* netmask bits - -1 if not contiguous */
struct in_addr brd; /* peer address */
unsigned system : 1; /* System alias ? */
struct ncprange ifa; /* local address/mask */
struct ncpaddr peer; /* peer address */
};
struct iface {
@ -41,24 +40,24 @@ struct iface {
int flags; /* Interface flags (IFF_*) */
int mtu; /* struct tuninfo MTU */
int in_addrs; /* How many in_addr's */
struct iface_addr *in_addr; /* Array of addresses (malloc'd) */
int addrs; /* How many in_addr's */
struct iface_addr *addr; /* Array of addresses (malloc'd) */
};
#define IFACE_CLEAR_ALL 0 /* Nuke 'em all */
#define IFACE_CLEAR_ALIASES 1 /* Leave the IPCP address */
#define IFACE_CLEAR_ALIASES 1 /* Leave the NCP address */
#define IFACE_ADD_LAST 0 /* Just another alias */
#define IFACE_ADD_FIRST 1 /* The IPCP address */
#define IFACE_FORCE_ADD 2 /* OR'd with IFACE_ADD_{FIRST,LAST} */
#define iface_Clear iface_inClear /* Same for now */
#define IFACE_SYSTEM 4 /* Set/clear SYSTEM entries */
extern struct iface *iface_Create(const char *name);
extern void iface_inClear(struct iface *, int);
extern int iface_inAdd(struct iface *, struct in_addr, struct in_addr,
struct in_addr, int);
extern int iface_inDelete(struct iface *, struct in_addr);
extern void iface_Clear(struct iface *, struct ncp *, int, int);
extern int iface_Add(struct iface *, struct ncp *, const struct ncprange *,
const struct ncpaddr *, int);
extern int iface_Delete(struct iface *, struct ncp *, const struct ncpaddr *);
extern int iface_Show(struct cmdargs const *);
extern int iface_SetFlags(const char *, int);
extern int iface_ClearFlags(const char *, int);

View File

@ -33,6 +33,10 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifndef NOINET6
#include <netinet/icmp6.h>
#include <netinet/ip6.h>
#endif
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
@ -40,7 +44,9 @@
#include <sys/un.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
@ -57,6 +63,8 @@
#include "throughput.h"
#include "iplist.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -67,9 +75,10 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "tun.h"
#include "ip.h"
#define OPCODE_QUERY 0
@ -155,54 +164,90 @@ PortMatch(int op, u_short pport, u_short rport)
}
/*
* Check a packet against a defined filter
* Returns 0 to accept the packet, non-zero to drop the packet
* Check a packet against the given filter
* Returns 0 to accept the packet, non-zero to drop the packet.
* If psecs is not NULL, populate it with the timeout associated
* with the filter rule matched.
*
* If filtering is enabled, the initial fragment of a datagram must
* contain the complete protocol header, and subsequent fragments
* must not attempt to over-write it.
* If filtering is enabled, the initial fragment of a datagram must
* contain the complete protocol header, and subsequent fragments
* must not attempt to over-write it.
*
* One (and only one) of pip or pip6 must be set.
*/
static int
FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
int
FilterCheck(const unsigned char *packet, u_int32_t family,
const struct filter *filter, unsigned *psecs)
{
int gotinfo; /* true if IP payload decoded */
int cproto; /* P_* protocol type if (gotinfo) */
int cproto; /* IPPROTO_* protocol number if (gotinfo) */
int estab, syn, finrst; /* TCP state flags if (gotinfo) */
u_short sport, dport; /* src, dest port from packet if (gotinfo) */
int n; /* filter rule to process */
int len; /* bytes used in dbuff */
int didname; /* true if filter header printed */
int match; /* true if condition matched */
int mindata; /* minimum data size or zero */
const struct filterent *fp = filter->rule;
char dbuff[100], dstip[16];
char dbuff[100], dstip[16], prototxt[16];
struct protoent *pe;
struct ncpaddr srcaddr, dstaddr;
const char *payload; /* IP payload */
int datalen; /* IP datagram length */
if (fp->f_action == A_NONE)
return 0; /* No rule is given. Permit this packet */
/*
* Deny any packet fragment that tries to over-write the header.
* Since we no longer have the real header available, punt on the
* largest normal header - 20 bytes for TCP without options, rounded
* up to the next possible fragment boundary. Since the smallest
* `legal' MTU is 576, and the smallest recommended MTU is 296, any
* fragmentation within this range is dubious at best
*/
len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */
if (len > 0) { /* Not first fragment within datagram */
if (len < (24 >> 3)) { /* don't allow fragment to over-write header */
log_Printf(LogFILTER, " error: illegal header\n");
return 1;
#ifndef NOINET6
if (family == AF_INET6) {
const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
datalen = ntohs(pip6->ip6_plen); /* XXX: Wrong ? */
payload = packet + sizeof *pip6; /* XXX: Wrong ? */
cproto = pip6->ip6_nxt;
} else
#endif
{
/*
* Deny any packet fragment that tries to over-write the header.
* Since we no longer have the real header available, punt on the
* largest normal header - 20 bytes for TCP without options, rounded
* up to the next possible fragment boundary. Since the smallest
* `legal' MTU is 576, and the smallest recommended MTU is 296, any
* fragmentation within this range is dubious at best
*/
const struct ip *pip = (const struct ip *)packet;
len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */
if (len > 0) { /* Not first fragment within datagram */
if (len < (24 >> 3)) { /* don't allow fragment to over-write header */
log_Printf(LogFILTER, " error: illegal header\n");
return 1;
}
/* permit fragments on in and out filter */
if (!filter->fragok) {
log_Printf(LogFILTER, " error: illegal fragmentation\n");
return 1;
} else
return 0;
}
/* permit fragments on in and out filter */
if (!filter->fragok) {
log_Printf(LogFILTER, " error: illegal fragmentation\n");
return 1;
} else
return 0;
}
cproto = gotinfo = estab = syn = finrst = didname = 0;
ncpaddr_setip4(&srcaddr, pip->ip_src);
ncpaddr_setip4(&dstaddr, pip->ip_dst);
datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
payload = packet + (pip->ip_hl << 2);
cproto = pip->ip_p;
}
if ((pe = getprotobynumber(cproto)) == NULL)
snprintf(prototxt, sizeof prototxt, "%d", cproto);
else
snprintf(prototxt, sizeof prototxt, "%s", pe->p_name);
gotinfo = estab = syn = finrst = didname = 0;
sport = dport = 0;
for (n = 0; n < MAXFILTERS; ) {
if (fp->f_action == A_NONE) {
n++;
@ -216,99 +261,76 @@ FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
}
match = 0;
if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
fp->f_src.mask.s_addr) &&
!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
fp->f_dst.mask.s_addr)) {
if (fp->f_proto != P_NONE) {
if ((ncprange_family(&fp->f_src) == AF_UNSPEC ||
ncprange_contains(&fp->f_src, &srcaddr)) &&
(ncprange_family(&fp->f_dst) == AF_UNSPEC ||
ncprange_contains(&fp->f_dst, &dstaddr))) {
if (fp->f_proto != 0) {
if (!gotinfo) {
const char *ptop = (const char *) pip + (pip->ip_hl << 2);
const struct tcphdr *th;
const struct udphdr *uh;
const struct icmp *ih;
int datalen; /* IP datagram length */
#ifndef NOINET6
const struct icmp6_hdr *ih6;
#endif
mindata = 0;
sport = dport = 0;
estab = syn = finrst = -1;
datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
switch (pip->ip_p) {
switch (cproto) {
case IPPROTO_ICMP:
cproto = P_ICMP;
if (datalen < 8) { /* ICMP must be at least 8 octets */
log_Printf(LogFILTER, " error: ICMP must be at least 8 octets\n");
return 1;
}
ih = (const struct icmp *) ptop;
sport = ih->icmp_type;
estab = syn = finrst = -1;
mindata = 8; /* ICMP must be at least 8 octets */
ih = (const struct icmp *)payload;
sport = ntohs(ih->icmp_type);
if (log_IsKept(LogDEBUG))
snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
break;
case IPPROTO_IGMP:
cproto = P_IGMP;
if (datalen < 8) { /* IGMP uses 8-octet messages */
log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
return 1;
}
estab = syn = finrst = -1;
sport = ntohs(0);
#ifndef NOINET6
case IPPROTO_ICMPV6:
mindata = 8; /* ICMP must be at least 8 octets */
ih6 = (const struct icmp6_hdr *)payload;
sport = ntohs(ih6->icmp6_type);
if (log_IsKept(LogDEBUG))
snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
break;
#endif
case IPPROTO_IGMP:
mindata = 8; /* IGMP uses 8-octet messages */
break;
#ifdef IPPROTO_GRE
case IPPROTO_GRE:
cproto = P_GRE;
if (datalen < 2) { /* GRE uses 2-octet+ messages */
log_Printf(LogFILTER, " error: GRE must be at least 2 octets\n");
return 1;
}
estab = syn = finrst = -1;
sport = ntohs(0);
mindata = 2; /* GRE uses 2-octet+ messages */
break;
#endif
#ifdef IPPROTO_OSPFIGP
case IPPROTO_OSPFIGP:
cproto = P_OSPF;
if (datalen < 8) { /* IGMP uses 8-octet messages */
log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
return 1;
}
estab = syn = finrst = -1;
sport = ntohs(0);
mindata = 8; /* IGMP uses 8-octet messages */
break;
#endif
case IPPROTO_ESP:
cproto = P_ESP;
estab = syn = finrst = -1;
sport = ntohs(0);
#ifndef NOINET6
case IPPROTO_IPV6:
mindata = 20; /* RFC2893 Section 3.5: 5 * 32bit words */
break;
case IPPROTO_AH:
cproto = P_AH;
estab = syn = finrst = -1;
sport = ntohs(0);
break;
case IPPROTO_IPIP:
cproto = P_IPIP;
sport = dport = 0;
estab = syn = finrst = -1;
break;
case IPPROTO_UDP:
cproto = P_UDP;
if (datalen < 8) { /* UDP header is 8 octets */
log_Printf(LogFILTER, " error: UDP/IPIP"
" must be at least 8 octets\n");
return 1;
}
#endif
uh = (const struct udphdr *) ptop;
case IPPROTO_UDP:
mindata = 8; /* UDP header is 8 octets */
uh = (const struct udphdr *)payload;
sport = ntohs(uh->uh_sport);
dport = ntohs(uh->uh_dport);
estab = syn = finrst = -1;
if (log_IsKept(LogDEBUG))
snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
sport, dport);
break;
case IPPROTO_TCP:
cproto = P_TCP;
th = (const struct tcphdr *) ptop;
/* TCP headers are variable length. The following code
th = (const struct tcphdr *)payload;
/*
* TCP headers are variable length. The following code
* ensures that the TCP header length isn't de-referenced if
* the datagram is too short
*/
@ -331,8 +353,13 @@ FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
}
break;
default:
log_Printf(LogFILTER, " error: unknown protocol\n");
return 1; /* We'll block unknown type of packet */
break;
}
if (datalen < mindata) {
log_Printf(LogFILTER, " error: proto %s must be at least"
" %d octets\n", prototxt, mindata);
return 1;
}
if (log_IsKept(LogDEBUG)) {
@ -342,11 +369,11 @@ FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
", estab = %d, syn = %d, finrst = %d",
estab, syn, finrst);
}
log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
filter_Proto2Nam(cproto), dbuff);
log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", prototxt, dbuff);
}
gotinfo = 1;
}
if (log_IsKept(LogDEBUG)) {
if (fp->f_srcop != OP_NONE) {
snprintf(dbuff, sizeof dbuff, ", src %s %d",
@ -362,9 +389,8 @@ FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
*dbuff = '\0';
log_Printf(LogDEBUG, " rule = %d: Address match, "
"check against proto %s%s, action = %s\n",
n, filter_Proto2Nam(fp->f_proto),
dbuff, filter_Action2Nam(fp->f_action));
"check against proto %d%s, action = %s\n",
n, fp->f_proto, dbuff, filter_Action2Nam(fp->f_action));
}
if (cproto == fp->f_proto) {
@ -398,24 +424,23 @@ FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
if (strcmp(filter->name, "DIAL") == 0) {
/* If dial filter then even print out accept packets */
if (log_IsKept(LogFILTER)) {
snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
log_Printf(LogFILTER, "%sbound rule = %d accept %s "
"src = %s/%d dst = %s/%d\n",
filter->name, n, filter_Proto2Nam(cproto),
inet_ntoa(pip->ip_src), sport, dstip, dport);
"src = %s:%d dst = %s:%d\n", filter->name, n, prototxt,
ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
}
}
return 0;
} else {
if (log_IsKept(LogFILTER)) {
snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
log_Printf(LogFILTER,
"%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
filter->name, n, filter_Proto2Nam(cproto),
inet_ntoa(pip->ip_src), sport, dstip, dport);
filter->name, n, prototxt,
ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
}
return 1;
} /* Explict math. Deny this packet */
} /* Explict match. Deny this packet */
}
} else {
n++;
@ -424,31 +449,16 @@ FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
}
if (log_IsKept(LogFILTER)) {
snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
log_Printf(LogFILTER,
"%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
filter->name, filter_Proto2Nam(cproto),
inet_ntoa(pip->ip_src), sport, dstip, dport);
filter->name, prototxt, ncpaddr_ntoa(&srcaddr), sport,
dstip, dport);
}
return 1; /* No rule is mached. Deny this packet */
return 1; /* No rule matched, deny this packet */
}
#ifdef notdef
static void
IcmpError(struct ip *pip, int code)
{
struct mbuf *bp;
if (pip->ip_p != IPPROTO_ICMP) {
bp = m_get(m_len, MB_IPIN);
memcpy(MBUF_CTOP(bp), ptr, m_len);
vj_SendFrame(bp);
ipcp_AddOutOctets(m_len);
}
}
#endif
static void
ip_LogDNS(const struct udphdr *uh, const char *direction)
{
@ -508,29 +518,60 @@ ip_LogDNS(const struct udphdr *uh, const char *direction)
}
/*
* For debugging aid.
* Check if the given packet matches the given filter.
* One of pip or pip6 must be set.
*/
int
PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
struct filter *filter, const char *prefix, unsigned *psecs)
PacketCheck(struct bundle *bundle, u_int32_t family,
const unsigned char *packet, int nb, struct filter *filter,
const char *prefix, unsigned *psecs)
{
static const char *const TcpFlags[] = {
"FIN", "SYN", "RST", "PSH", "ACK", "URG"
};
struct ip *pip;
struct tcphdr *th;
struct udphdr *uh;
struct icmp *icmph;
unsigned char *ptop;
int mask, len, n, pri, logit, loglen, result;
const struct tcphdr *th;
const struct udphdr *uh;
const struct icmp *icmph;
#ifndef NOINET6
const struct icmp6_hdr *icmp6h;
#endif
const unsigned char *payload;
struct ncpaddr srcaddr, dstaddr;
int cproto, mask, len, n, pri, logit, loglen, result;
char logbuf[200];
int datalen, frag;
u_char tos;
logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
(!filter || filter->logok);
loglen = 0;
pri = 0;
pip = (struct ip *)cp;
#ifndef NOINET6
if (family == AF_INET6) {
const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
datalen = ntohs(pip6->ip6_plen);
payload = packet + sizeof *pip6;
cproto = pip6->ip6_nxt;
tos = 0; /* XXX: ??? */
frag = 0; /* XXX: ??? */
} else
#endif
{
const struct ip *pip = (const struct ip *)packet;
ncpaddr_setip4(&srcaddr, pip->ip_src);
ncpaddr_setip4(&dstaddr, pip->ip_dst);
datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
payload = packet + (pip->ip_hl << 2);
cproto = pip->ip_p;
tos = pip->ip_tos;
frag = ntohs(pip->ip_off) & IP_OFFMASK;
}
uh = NULL;
if (logit && loglen < sizeof logbuf) {
@ -542,57 +583,70 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
snprintf(logbuf + loglen, sizeof logbuf - loglen, " ");
loglen += strlen(logbuf + loglen);
}
ptop = (cp + (pip->ip_hl << 2));
switch (pip->ip_p) {
switch (cproto) {
case IPPROTO_ICMP:
if (logit && loglen < sizeof logbuf) {
len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *icmph;
icmph = (struct icmp *) ptop;
len = datalen - sizeof *icmph;
icmph = (const struct icmp *)payload;
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
"ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmph->icmp_type);
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), icmph->icmp_type,
len, nb);
"%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
loglen += strlen(logbuf + loglen);
}
break;
#ifndef NOINET6
case IPPROTO_ICMPV6:
if (logit && loglen < sizeof logbuf) {
len = datalen - sizeof *icmp6h;
icmp6h = (const struct icmp6_hdr *)payload;
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmp6h->icmp6_type);
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
loglen += strlen(logbuf + loglen);
}
break;
#endif
case IPPROTO_UDP:
uh = (struct udphdr *) ptop;
if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
uh = (const struct udphdr *)payload;
if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
pri++;
if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
ntohs(uh->uh_dport)))
if (!frag && ncp_IsUrgentUdpPort(&bundle->ncp, ntohs(uh->uh_sport),
ntohs(uh->uh_dport)))
pri++;
if (logit && loglen < sizeof logbuf) {
len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *uh;
len = datalen - sizeof *uh;
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
"UDP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport),
"%s:%d (%d/%d)", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport),
len, nb);
loglen += strlen(logbuf + loglen);
}
if (Enabled(bundle, OPT_FILTERDECAP) &&
ptop[sizeof *uh] == HDLC_ADDR && ptop[sizeof *uh + 1] == HDLC_UI) {
payload[sizeof *uh] == HDLC_ADDR &&
payload[sizeof *uh + 1] == HDLC_UI) {
u_short proto;
const char *type;
memcpy(&proto, ptop + sizeof *uh + 2, sizeof proto);
memcpy(&proto, payload + sizeof *uh + 2, sizeof proto);
type = NULL;
switch (ntohs(proto)) {
case PROTO_IP:
snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
result = PacketCheck(bundle, ptop + sizeof *uh + 4,
nb - (ptop - cp) - sizeof *uh - 4, filter,
result = PacketCheck(bundle, AF_INET, payload + sizeof *uh + 4,
nb - (payload - packet) - sizeof *uh - 4, filter,
logbuf, psecs);
if (result != -2)
return result;
@ -623,12 +677,11 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
#ifdef IPPROTO_GRE
case IPPROTO_GRE:
if (logit && loglen < sizeof logbuf) {
len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"GRE: %s ---> ", inet_ntoa(pip->ip_src));
"GRE: %s ---> ", ncpaddr_ntoa(&srcaddr));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
"%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
loglen += strlen(logbuf + loglen);
}
break;
@ -637,43 +690,64 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
#ifdef IPPROTO_OSPFIGP
case IPPROTO_OSPFIGP:
if (logit && loglen < sizeof logbuf) {
len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"OSPF: %s ---> ", inet_ntoa(pip->ip_src));
"OSPF: %s ---> ", ncpaddr_ntoa(&srcaddr));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
"%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
loglen += strlen(logbuf + loglen);
}
break;
#endif
#ifndef NOINET6
case IPPROTO_IPV6:
if (logit && loglen < sizeof logbuf) {
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"IPv6: %s ---> ", ncpaddr_ntoa(&srcaddr));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
loglen += strlen(logbuf + loglen);
}
if (Enabled(bundle, OPT_FILTERDECAP)) {
snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
result = PacketCheck(bundle, AF_INET6, payload, nb - (payload - packet),
filter, logbuf, psecs);
if (result != -2)
return result;
}
break;
#endif
case IPPROTO_IPIP:
if (logit && loglen < sizeof logbuf) {
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"IPIP: %s ---> ", inet_ntoa(pip->ip_src));
"IPIP: %s ---> ", ncpaddr_ntoa(&srcaddr));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s", inet_ntoa(pip->ip_dst));
"%s", ncpaddr_ntoa(&dstaddr));
loglen += strlen(logbuf + loglen);
}
if (((struct ip *)ptop)->ip_v == 4) {
snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
result = PacketCheck(bundle, ptop, nb - (ptop - cp), filter,
logbuf, psecs);
if (result != -2)
return result;
}
if (Enabled(bundle, OPT_FILTERDECAP) &&
((const struct ip *)payload)->ip_v == 4) {
snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
result = PacketCheck(bundle, AF_INET, payload, nb - (payload - packet),
filter, logbuf, psecs);
if (result != -2)
return result;
}
break;
case IPPROTO_ESP:
if (logit && loglen < sizeof logbuf) {
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"ESP: %s ---> ", inet_ntoa(pip->ip_src));
"ESP: %s ---> ", ncpaddr_ntoa(&srcaddr));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
inet_ntoa(pip->ip_dst), ptop);
ncpaddr_ntoa(&dstaddr), payload);
loglen += strlen(logbuf + loglen);
}
break;
@ -681,44 +755,43 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
case IPPROTO_AH:
if (logit && loglen < sizeof logbuf) {
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"AH: %s ---> ", inet_ntoa(pip->ip_src));
"AH: %s ---> ", ncpaddr_ntoa(&srcaddr));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
inet_ntoa(pip->ip_dst), ptop + sizeof(u_int32_t));
ncpaddr_ntoa(&dstaddr), payload + sizeof(u_int32_t));
loglen += strlen(logbuf + loglen);
}
break;
case IPPROTO_IGMP:
if (logit && loglen < sizeof logbuf) {
uh = (struct udphdr *) ptop;
uh = (const struct udphdr *)payload;
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src),
"IGMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr),
ntohs(uh->uh_sport));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
"%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport));
loglen += strlen(logbuf + loglen);
}
break;
case IPPROTO_TCP:
th = (struct tcphdr *) ptop;
if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
th = (const struct tcphdr *)payload;
if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
pri++;
if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
ntohs(th->th_dport)))
if (!frag && ncp_IsUrgentTcpPort(&bundle->ncp, ntohs(th->th_sport),
ntohs(th->th_dport)))
pri++;
if (logit && loglen < sizeof logbuf) {
len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
len = datalen - (th->th_off << 2);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
"TCP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(th->th_sport));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
"%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(th->th_dport));
loglen += strlen(logbuf + loglen);
n = 0;
for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
@ -733,10 +806,9 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
(u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
loglen += strlen(logbuf + loglen);
if ((th->th_flags & TH_SYN) && nb > 40) {
u_short *sp;
const u_short *sp;
ptop += 20;
sp = (u_short *) ptop;
sp = (const u_short *)(payload + 20);
if (ntohs(sp[0]) == 0x0204) {
snprintf(logbuf + loglen, sizeof logbuf - loglen,
" MSS = %d", ntohs(sp[1]));
@ -749,15 +821,21 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
default:
if (prefix)
return -2;
if (logit && loglen < sizeof logbuf) {
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr));
loglen += strlen(logbuf + loglen);
snprintf(logbuf + loglen, sizeof logbuf - loglen,
"%s (%d)", ncpaddr_ntoa(&dstaddr), nb);
loglen += strlen(logbuf + loglen);
}
break;
}
if (filter && FilterCheck(pip, filter, psecs)) {
if (filter && FilterCheck(packet, family, filter, psecs)) {
if (logit)
log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
#ifdef notdef
if (direction == 0)
IcmpError(pip, pri);
#endif
result = -1;
} else {
/* Check Keep Alive filter */
@ -765,7 +843,8 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
unsigned alivesecs;
alivesecs = 0;
if (filter && FilterCheck(pip, &bundle->filter.alive, &alivesecs))
if (filter &&
FilterCheck(packet, family, &bundle->filter.alive, &alivesecs))
log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
else if (psecs != NULL) {
if(*psecs == 0)
@ -789,47 +868,37 @@ PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
return result;
}
struct mbuf *
ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
static int
ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af)
{
int nb, nw;
struct tun_data tun;
struct ip *pip;
char *data;
unsigned secs, alivesecs;
if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
m_freem(bp);
return NULL;
}
m_settype(bp, MB_IPIN);
nb = m_length(bp);
if (nb > sizeof tun.data) {
log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
l->name, nb, (int)(sizeof tun.data));
m_freem(bp);
return NULL;
return 0;
}
mbuf_Read(bp, tun.data, nb);
secs = 0;
if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in, NULL, &secs) < 0)
return NULL;
if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in,
NULL, &secs) < 0)
return 0;
pip = (struct ip *)tun.data;
alivesecs = 0;
if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) {
if (secs == 0)
secs = alivesecs;
bundle_StartIdleTimer(bundle, secs);
}
ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
if (bundle->dev.header) {
tun.header.family = htonl(AF_INET);
tun.header.family = htonl(af);
nb += sizeof tun - sizeof tun.data;
data = (char *)&tun;
} else
@ -844,94 +913,45 @@ ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
}
return nb;
}
struct mbuf *
ipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
{
int nb;
if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n");
m_freem(bp);
return NULL;
}
m_settype(bp, MB_IPIN);
nb = ip_Input(bundle, l, bp, AF_INET);
ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
return NULL;
}
void
ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
#ifndef NOINET6
struct mbuf *
ipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
{
struct mbuf *bp;
int nb;
if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
else {
/*
* We allocate an extra 6 bytes, four at the front and two at the end.
* This is an optimisation so that we need to do less work in
* m_prepend() in acf_LayerPush() and proto_LayerPush() and
* appending in hdlc_LayerPush().
*/
bp = m_get(count + 6, MB_IPOUT);
bp->m_offset += 4;
bp->m_len -= 6;
memcpy(MBUF_CTOP(bp), ptr, count);
m_enqueue(ipcp->Queue + pri, bp);
}
}
void
ip_DeleteQueue(struct ipcp *ipcp)
{
struct mqueue *queue;
for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
while (queue->top)
m_freem(m_dequeue(queue));
}
size_t
ip_QueueLen(struct ipcp *ipcp)
{
struct mqueue *queue;
size_t result;
result = 0;
for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
result += queue->len;
return result;
}
int
ip_PushPacket(struct link *l, struct bundle *bundle)
{
struct ipcp *ipcp = &bundle->ncp.ipcp;
struct mqueue *queue;
struct mbuf *bp;
struct ip *pip;
int m_len;
u_int32_t secs = 0;
unsigned alivesecs = 0;
if (ipcp->fsm.state != ST_OPENED)
return 0;
/*
* If ccp is not open but is required, do nothing.
*/
if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
return 0;
if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) {
log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n");
m_freem(bp);
return NULL;
}
queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
do {
if (queue->top) {
bp = m_dequeue(queue);
bp = mbuf_Read(bp, &secs, sizeof secs);
bp = m_pullup(bp);
m_len = m_length(bp);
pip = (struct ip *)MBUF_CTOP(bp);
if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
if (secs == 0)
secs = alivesecs;
bundle_StartIdleTimer(bundle, secs);
}
link_PushPacket(l, bp, bundle, 0, PROTO_IP);
ipcp_AddOutOctets(ipcp, m_len);
return 1;
}
} while (queue-- != ipcp->Queue);
m_settype(bp, MB_IPV6IN);
return 0;
nb = ip_Input(bundle, l, bp, AF_INET6);
ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb);
return NULL;
}
#endif

View File

@ -34,9 +34,11 @@ struct link;
struct bundle;
extern int ip_PushPacket(struct link *, struct bundle *);
extern int PacketCheck(struct bundle *, unsigned char *, int, struct filter *,
const char *, unsigned *secs);
extern void ip_Enqueue(struct ipcp *, int, char *, int);
extern struct mbuf *ip_Input(struct bundle *, struct link *, struct mbuf *);
extern void ip_DeleteQueue(struct ipcp *);
extern size_t ip_QueueLen(struct ipcp *);
extern int PacketCheck(struct bundle *, u_int32_t, const unsigned char *, int,
struct filter *, const char *, unsigned *secs);
extern int FilterCheck(const unsigned char *, u_int32_t, const struct filter *,
unsigned *);
extern struct mbuf *ipv4_Input(struct bundle *, struct link *, struct mbuf *);
#ifndef NOINET6
extern struct mbuf *ipv6_Input(struct bundle *, struct link *, struct mbuf *);
#endif

View File

@ -71,6 +71,8 @@
#include "lqr.h"
#include "hdlc.h"
#include "lcp.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -83,6 +85,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "id.h"
#include "arp.h"
@ -90,101 +94,12 @@
#include "prompt.h"
#include "route.h"
#include "iface.h"
#include "ip.h"
#undef REJECTED
#define REJECTED(p, x) ((p)->peer_reject & (1<<(x)))
#define issep(ch) ((ch) == ' ' || (ch) == '\t')
#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
static u_short default_urgent_tcp_ports[] = {
21, /* ftp */
22, /* ssh */
23, /* telnet */
513, /* login */
514, /* shell */
543, /* klogin */
544 /* kshell */
};
static u_short default_urgent_udp_ports[] = { };
#define NDEFTCPPORTS \
(sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0])
#define NDEFUDPPORTS \
(sizeof default_urgent_udp_ports / sizeof default_urgent_udp_ports[0])
int
ipcp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
{
int f;
for (f = 0; f < range->nports; f++)
if (range->port[f] == src || range->port[f] == dst)
return 1;
return 0;
}
void
ipcp_AddUrgentPort(struct port_range *range, u_short port)
{
u_short *newport;
int p;
if (range->nports == range->maxports) {
range->maxports += 10;
newport = (u_short *)realloc(range->port,
range->maxports * sizeof(u_short));
if (newport == NULL) {
log_Printf(LogERROR, "ipcp_AddUrgentPort: realloc: %s\n",
strerror(errno));
range->maxports -= 10;
return;
}
range->port = newport;
}
for (p = 0; p < range->nports; p++)
if (range->port[p] == port) {
log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
break;
} else if (range->port[p] > port) {
memmove(range->port + p + 1, range->port + p,
(range->nports - p) * sizeof(u_short));
range->port[p] = port;
range->nports++;
break;
}
if (p == range->nports)
range->port[range->nports++] = port;
}
void
ipcp_RemoveUrgentPort(struct port_range *range, u_short port)
{
int p;
for (p = 0; p < range->nports; p++)
if (range->port[p] == port) {
if (p != range->nports - 1)
memmove(range->port + p, range->port + p + 1,
(range->nports - p - 1) * sizeof(u_short));
range->nports--;
return;
}
if (p == range->nports)
log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
}
void
ipcp_ClearUrgentPorts(struct port_range *range)
{
range->nports = 0;
}
struct compreq {
u_short proto;
u_char slots;
@ -327,7 +242,7 @@ ipcp_LoadDNS(struct ipcp *ipcp)
ch = *ncp;
*ncp = '\0';
if (n < 2 && inet_aton(cp, ipcp->ns.dns + n))
if (n < 2 && inet_aton(cp, ipcp->ns.dns))
n++;
*ncp = ch;
@ -344,7 +259,7 @@ ipcp_LoadDNS(struct ipcp *ipcp)
ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr;
ipcp->ns.dns[1].s_addr = INADDR_ANY;
}
bundle_AdjustDNS(ipcp->fsm.bundle, ipcp->ns.dns);
bundle_AdjustDNS(ipcp->fsm.bundle);
}
} else
log_Printf(LogERROR, "Failed to stat opened %s: %s\n",
@ -431,7 +346,6 @@ int
ipcp_Show(struct cmdargs const *arg)
{
struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
int p;
prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
State2Nam(ipcp->fsm.state));
@ -441,12 +355,7 @@ ipcp_Show(struct cmdargs const *arg)
prompt_Printf(arg->prompt, " My side: %s, %s\n",
inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
prompt_Printf(arg->prompt, " Queued packets: %lu\n",
(unsigned long)ip_QueueLen(ipcp));
}
if (ipcp->route) {
prompt_Printf(arg->prompt, "\n");
route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1);
(unsigned long)ipcp_QueueLen(ipcp));
}
prompt_Printf(arg->prompt, "\nDefaults:\n");
@ -454,9 +363,8 @@ ipcp_Show(struct cmdargs const *arg)
" REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
prompt_Printf(arg->prompt, " My Address: %s/%d",
inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask));
prompt_Printf(arg->prompt, " My Address: %s\n",
ncprange_ntoa(&ipcp->cfg.my_range));
if (ipcp->cfg.HaveTriggerAddress)
prompt_Printf(arg->prompt, " Trigger address: %s\n",
inet_ntoa(ipcp->cfg.TriggerAddress));
@ -469,15 +377,15 @@ ipcp_Show(struct cmdargs const *arg)
prompt_Printf(arg->prompt, " His Address: %s\n",
ipcp->cfg.peer_list.src);
else
prompt_Printf(arg->prompt, " His Address: %s/%d\n",
inet_ntoa(ipcp->cfg.peer_range.ipaddr),
ipcp->cfg.peer_range.width);
prompt_Printf(arg->prompt, " His Address: %s\n",
ncprange_ntoa(&ipcp->cfg.peer_range));
prompt_Printf(arg->prompt, " DNS: %s",
ipcp->cfg.ns.dns[0].s_addr == INADDR_NONE ?
"none" : inet_ntoa(ipcp->cfg.ns.dns[0]));
if (ipcp->cfg.ns.dns[1].s_addr != INADDR_NONE)
prompt_Printf(arg->prompt, ", %s", inet_ntoa(ipcp->cfg.ns.dns[1]));
prompt_Printf(arg->prompt, ", %s",
inet_ntoa(ipcp->cfg.ns.dns[1]));
prompt_Printf(arg->prompt, ", %s\n",
command_ShowNegval(ipcp->cfg.ns.dns_neg));
prompt_Printf(arg->prompt, " Resolver DNS: %s",
@ -485,32 +393,12 @@ ipcp_Show(struct cmdargs const *arg)
"none" : inet_ntoa(ipcp->ns.dns[0]));
if (ipcp->ns.dns[1].s_addr != INADDR_NONE &&
ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr)
prompt_Printf(arg->prompt, ", %s", inet_ntoa(ipcp->ns.dns[1]));
prompt_Printf(arg->prompt, ", %s",
inet_ntoa(ipcp->ns.dns[1]));
prompt_Printf(arg->prompt, "\n NetBIOS NS: %s, ",
inet_ntoa(ipcp->cfg.ns.nbns[0]));
prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
prompt_Printf(arg->prompt, " Urgent ports\n");
prompt_Printf(arg->prompt, " TCP: ");
if (ipcp->cfg.urgent.tcp.nports == 0)
prompt_Printf(arg->prompt, "none");
else
for (p = 0; p < ipcp->cfg.urgent.tcp.nports; p++) {
if (p)
prompt_Printf(arg->prompt, ", ");
prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.tcp.port[p]);
}
prompt_Printf(arg->prompt, "\n UDP: ");
if (ipcp->cfg.urgent.udp.nports == 0)
prompt_Printf(arg->prompt, "none");
else
for (p = 0; p < ipcp->cfg.urgent.udp.nports; p++) {
if (p)
prompt_Printf(arg->prompt, ", ");
prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.udp.port[p]);
}
prompt_Printf(arg->prompt, "\n TOS: %s\n\n",
ipcp->cfg.urgent.tos ? "yes" : "no");
prompt_Printf(arg->prompt, "%s\n",
inet_ntoa(ipcp->cfg.ns.nbns[1]));
throughput_disp(&ipcp->throughput, arg->prompt);
@ -547,6 +435,7 @@ ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
const struct fsm_parent *parent)
{
struct hostent *hp;
struct in_addr host;
char name[MAXHOSTNAMELEN];
static const char * const timer_names[] =
{"IPCP restart", "IPCP openmode", "IPCP stopped"};
@ -554,17 +443,20 @@ ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
bundle, l, parent, &ipcp_Callbacks, timer_names);
ipcp->route = NULL;
ipcp->cfg.vj.slots = DEF_VJ_STATES;
ipcp->cfg.vj.slotcomp = 1;
memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
host.s_addr = htonl(INADDR_LOOPBACK);
ipcp->cfg.netmask.s_addr = INADDR_ANY;
if (gethostname(name, sizeof name) == 0) {
hp = gethostbyname(name);
if (hp && hp->h_addrtype == AF_INET)
memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
if (hp && hp->h_addrtype == AF_INET && hp->h_length == sizeof host.s_addr)
memcpy(&host.s_addr, hp->h_addr, sizeof host.s_addr);
}
ipcp->cfg.netmask.s_addr = INADDR_ANY;
memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
ncprange_setip4(&ipcp->cfg.my_range, host, ipcp->cfg.netmask);
ncprange_setip4(&ipcp->cfg.peer_range, ipcp->cfg.netmask, ipcp->cfg.netmask);
iplist_setsrc(&ipcp->cfg.peer_list, "");
ipcp->cfg.HaveTriggerAddress = 0;
@ -574,17 +466,6 @@ ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
ipcp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
memcpy(ipcp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
NDEFTCPPORTS * sizeof(u_short));
ipcp->cfg.urgent.tos = 1;
ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = NDEFUDPPORTS;
ipcp->cfg.urgent.udp.port = (u_short *)malloc(NDEFUDPPORTS * sizeof(u_short));
memcpy(ipcp->cfg.urgent.udp.port, default_urgent_udp_ports,
NDEFUDPPORTS * sizeof(u_short));
ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
@ -605,16 +486,8 @@ ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
void
ipcp_Destroy(struct ipcp *ipcp)
{
if (ipcp->cfg.urgent.tcp.maxports) {
ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = 0;
free(ipcp->cfg.urgent.tcp.port);
ipcp->cfg.urgent.tcp.port = NULL;
}
if (ipcp->cfg.urgent.udp.maxports) {
ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = 0;
free(ipcp->cfg.urgent.udp.port);
ipcp->cfg.urgent.udp.port = NULL;
}
throughput_destroy(&ipcp->throughput);
if (ipcp->ns.resolv != NULL) {
free(ipcp->ns.resolv);
ipcp->ns.resolv = NULL;
@ -635,6 +508,8 @@ void
ipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
{
struct iface *iface = ipcp->fsm.bundle->iface;
struct ncpaddr ipaddr;
struct in_addr peer;
int pos, n;
ipcp->fsm.open_mode = 0;
@ -642,25 +517,24 @@ ipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
if (iplist_isvalid(&ipcp->cfg.peer_list)) {
/* Try to give the peer a previously configured IP address */
for (n = 0; n < iface->in_addrs; n++) {
pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd);
if (pos != -1) {
ipcp->cfg.peer_range.ipaddr =
iplist_setcurpos(&ipcp->cfg.peer_list, pos);
for (n = 0; n < iface->addrs; n++) {
if (!ncpaddr_getip4(&iface->addr[n].peer, &peer))
continue;
if ((pos = iplist_ip2pos(&ipcp->cfg.peer_list, peer)) != -1) {
ncpaddr_setip4(&ipaddr, iplist_setcurpos(&ipcp->cfg.peer_list, pos));
break;
}
}
if (n == iface->in_addrs)
if (n == iface->addrs)
/* Ok, so none of 'em fit.... pick a random one */
ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
ncpaddr_setip4(&ipaddr, iplist_setrandpos(&ipcp->cfg.peer_list));
ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
ipcp->cfg.peer_range.width = 32;
ncprange_sethost(&ipcp->cfg.peer_range, &ipaddr);
}
ipcp->heis1172 = 0;
ipcp->peer_req = 0;
ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip);
ipcp->peer_compproto = 0;
if (ipcp->cfg.HaveTriggerAddress) {
@ -677,17 +551,17 @@ ipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
* Otherwise, if we've used an IP number before and it's still within
* the network specified on the ``set ifaddr'' line, we really
* want to keep that IP number so that we can keep any existing
* connections that are bound to that IP (assuming we're not
* ``iface-alias''ing).
* connections that are bound to that IP.
*/
for (n = 0; n < iface->in_addrs; n++)
if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
(ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) {
ipcp->my_ip = iface->in_addr[n].ifa;
for (n = 0; n < iface->addrs; n++) {
ncprange_getaddr(&iface->addr[n].ifa, &ipaddr);
if (ncprange_contains(&ipcp->cfg.my_range, &ipaddr)) {
ncpaddr_getip4(&ipaddr, &ipcp->my_ip);
break;
}
if (n == iface->in_addrs)
ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
}
if (n == iface->addrs)
ncprange_getip4addr(&ipcp->cfg.my_range, &ipcp->my_ip);
}
if (IsEnabled(ipcp->cfg.vj.neg)
@ -705,98 +579,121 @@ ipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
ipcp->peer_reject = 0;
ipcp->my_reject = 0;
/* Copy startup values into ipcp->dns? */
/* Copy startup values into ipcp->ns.dns */
if (ipcp->cfg.ns.dns[0].s_addr != INADDR_NONE)
memcpy(ipcp->dns, ipcp->cfg.ns.dns, sizeof ipcp->dns);
else if (ipcp->ns.dns[0].s_addr != INADDR_NONE)
memcpy(ipcp->dns, ipcp->ns.dns, sizeof ipcp->dns);
else
ipcp->dns[0].s_addr = ipcp->dns[1].s_addr = INADDR_ANY;
if (ipcp->dns[1].s_addr == INADDR_NONE)
ipcp->dns[1] = ipcp->dns[0];
memcpy(ipcp->ns.dns, ipcp->cfg.ns.dns, sizeof ipcp->ns.dns);
}
static int
ipcp_doproxyall(struct bundle *bundle,
int (*proxyfun)(struct bundle *, struct in_addr, int), int s)
numaddresses(struct in_addr mask)
{
int n, ret;
struct sticky_route *rp;
struct in_addr addr;
struct ipcp *ipcp;
u_int32_t bit, haddr;
int n;
ipcp = &bundle->ncp.ipcp;
for (rp = ipcp->route; rp != NULL; rp = rp->next) {
if (rp->mask.s_addr == INADDR_BROADCAST)
continue;
n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1;
if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) {
addr = rp->dst;
while (n--) {
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr));
ret = (*proxyfun)(bundle, addr, s);
if (!ret)
return ret;
}
}
haddr = ntohl(mask.s_addr);
bit = 1;
n = 1;
do {
if (!(haddr & bit))
n <<= 1;
} while (bit <<= 1);
return n;
}
static int
ipcp_proxyarp(struct ipcp *ipcp,
int (*proxyfun)(struct bundle *, struct in_addr, int),
const struct iface_addr *addr)
{
struct bundle *bundle = ipcp->fsm.bundle;
struct in_addr peer, mask, ip;
int n, ret, s;
if (!ncpaddr_getip4(&addr->peer, &peer)) {
log_Printf(LogERROR, "Oops, ipcp_proxyarp() called with unexpected addr\n");
return 0;
}
return 0;
if ((s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
log_Printf(LogERROR, "ipcp_proxyarp: socket: %s\n",
strerror(errno));
return 0;
}
ret = 0;
if (Enabled(bundle, OPT_PROXYALL)) {
ncprange_getip4mask(&addr->ifa, &mask);
if ((n = numaddresses(mask)) > 256) {
log_Printf(LogWARN, "%s: Too many addresses for proxyall\n",
ncprange_ntoa(&addr->ifa));
return 0;
}
ip.s_addr = peer.s_addr & mask.s_addr;
if (n >= 4) {
ip.s_addr = htonl(ntohl(ip.s_addr) + 1);
n -= 2;
}
while (n) {
if (!((ip.s_addr ^ peer.s_addr) & mask.s_addr)) {
if (!(ret = (*proxyfun)(bundle, ip, s)))
break;
n--;
}
ip.s_addr = htonl(ntohl(ip.s_addr) + 1);
}
ret = !n;
} else if (Enabled(bundle, OPT_PROXY))
ret = (*proxyfun)(bundle, peer, s);
close(s);
return ret;
}
static int
ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
struct in_addr hisaddr, int silent)
ipcp_SetIPaddress(struct ipcp *ipcp, struct in_addr myaddr,
struct in_addr hisaddr)
{
struct in_addr mask, oaddr;
struct bundle *bundle = ipcp->fsm.bundle;
struct ncpaddr myncpaddr, hisncpaddr;
struct ncprange myrange, dst;
struct in_addr mask;
ncpaddr_setip4(&hisncpaddr, hisaddr);
ncpaddr_setip4(&myncpaddr, myaddr);
ncprange_sethost(&myrange, &myncpaddr);
mask = addr2mask(myaddr);
if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY &&
(bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr)
mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr;
if (ipcp->ifmask.s_addr != INADDR_ANY &&
(ipcp->ifmask.s_addr & mask.s_addr) == mask.s_addr)
ncprange_setip4mask(&myrange, ipcp->ifmask);
oaddr.s_addr = bundle->iface->in_addrs ?
bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY;
if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr,
IFACE_ADD_FIRST|IFACE_FORCE_ADD))
return -1;
if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &hisncpaddr,
IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
return 0;
if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1
&& myaddr.s_addr != oaddr.s_addr)
/* Nuke the old one */
iface_inDelete(bundle->iface, oaddr);
if (!Enabled(bundle, OPT_IFACEALIAS))
iface_Clear(bundle->iface, &bundle->ncp, AF_INET,
IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0)
rt_Update(bundle, hisaddr, myaddr);
if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
ncprange_sethost(&dst, &hisncpaddr);
rt_Update(bundle, &dst);
}
if (Enabled(bundle, OPT_SROUTES))
route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr,
bundle->ncp.ipcp.ns.dns);
route_Change(bundle, bundle->ncp.route, &myncpaddr, &hisncpaddr);
#ifndef NORADIUS
if (bundle->radius.valid)
route_Change(bundle, bundle->radius.routes, myaddr, hisaddr,
bundle->ncp.ipcp.ns.dns);
route_Change(bundle, bundle->radius.routes, &myncpaddr, &hisncpaddr);
#endif
if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) {
int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n",
strerror(errno));
else {
if (Enabled(bundle, OPT_PROXYALL))
ipcp_doproxyall(bundle, arp_SetProxy, s);
else if (Enabled(bundle, OPT_PROXY))
arp_SetProxy(bundle, hisaddr, s);
close(s);
}
}
return 0;
return 1; /* Ok */
}
static struct in_addr
@ -809,7 +706,7 @@ ChooseHisAddr(struct bundle *bundle, struct in_addr gw)
try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
f, inet_ntoa(try));
if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
if (ipcp_SetIPaddress(&bundle->ncp.ipcp, gw, try)) {
log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
break;
}
@ -876,16 +773,16 @@ IpcpSendConfigReq(struct fsm *fp)
}
}
if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
!REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS)) {
memcpy(o->data, &ipcp->dns[0].s_addr, 4);
INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
}
if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
if (!REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS)) {
memcpy(o->data, &ipcp->ns.dns[0].s_addr, 4);
INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
}
if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
!REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
memcpy(o->data, &ipcp->dns[1].s_addr, 4);
INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
if (!REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
memcpy(o->data, &ipcp->ns.dns[1].s_addr, 4);
INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
}
}
fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
@ -929,43 +826,41 @@ IpcpLayerFinish(struct fsm *fp)
throughput_log(&ipcp->throughput, LogIPCP, NULL);
}
/*
* Called from iface_Add() via ncp_IfaceAddrAdded()
*/
void
ipcp_CleanInterface(struct ipcp *ipcp)
ipcp_IfaceAddrAdded(struct ipcp *ipcp, const struct iface_addr *addr)
{
struct iface *iface = ipcp->fsm.bundle->iface;
struct bundle *bundle = ipcp->fsm.bundle;
if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) ||
Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) {
int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n",
strerror(errno));
else {
if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL))
ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s);
else if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s);
close(s);
}
}
if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL))
ipcp_proxyarp(ipcp, arp_SetProxy, addr);
}
iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL);
/*
* Called from iface_Clear() and iface_Delete() via ncp_IfaceAddrDeleted()
*/
void
ipcp_IfaceAddrDeleted(struct ipcp *ipcp, const struct iface_addr *addr)
{
struct bundle *bundle = ipcp->fsm.bundle;
if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL))
ipcp_proxyarp(ipcp, arp_ClearProxy, addr);
}
static void
IpcpLayerDown(struct fsm *fp)
{
/* About to come down */
static int recursing;
struct ipcp *ipcp = fsm2ipcp(fp);
const char *s;
static int recursing;
char addr[16];
if (!recursing++) {
if (ipcp->fsm.bundle->iface->in_addrs)
s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa);
else
s = "Interface configuration error !";
log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
snprintf(addr, sizeof addr, "%s", inet_ntoa(ipcp->my_ip));
log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, addr);
#ifndef NORADIUS
radius_Account(&fp->bundle->radius, &fp->bundle->radacct,
@ -977,7 +872,7 @@ IpcpLayerDown(struct fsm *fp)
* XXX this stuff should really live in the FSM. Our config should
* associate executable sections in files with events.
*/
if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) {
if (bundle_GetLabel(fp->bundle)) {
if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
LINKDOWNFILE, NULL, NULL) < 0)
@ -994,7 +889,7 @@ IpcpLayerDown(struct fsm *fp)
int
ipcp_InterfaceUp(struct ipcp *ipcp)
{
if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
if (!ipcp_SetIPaddress(ipcp, ipcp->my_ip, ipcp->peer_ip)) {
log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
return 0;
}
@ -1055,25 +950,19 @@ IpcpLayerUp(struct fsm *fp)
return 1;
}
static int
AcceptableAddr(const struct in_range *prange, struct in_addr ipaddr)
{
/* Is the given IP in the given range ? */
return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
(ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
}
static void
ipcp_ValidateReq(struct ipcp *ipcp, struct in_addr ip, struct fsm_decode *dec)
{
struct bundle *bundle = ipcp->fsm.bundle;
struct iface *iface = bundle->iface;
struct in_addr myaddr, peer;
int n;
if (iplist_isvalid(&ipcp->cfg.peer_list)) {
ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
if (ip.s_addr == INADDR_ANY ||
iplist_ip2pos(&ipcp->cfg.peer_list, ip) < 0 ||
ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, ip, 1)) {
!ipcp_SetIPaddress(ipcp, myaddr, ip)) {
log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
inet_ntoa(ip));
/*
@ -1081,15 +970,19 @@ ipcp_ValidateReq(struct ipcp *ipcp, struct in_addr ip, struct fsm_decode *dec)
* try NAKing with that so that we don't have to upset things
* too much.
*/
for (n = 0; n < iface->in_addrs; n++)
if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd) >= 0) {
ipcp->peer_ip = iface->in_addr[n].brd;
for (n = 0; n < iface->addrs; n++) {
if (!ncpaddr_getip4(&iface->addr[n].peer, &peer))
continue;
if (iplist_ip2pos(&ipcp->cfg.peer_list, peer) >= 0) {
ipcp->peer_ip = peer;
break;
}
}
if (n == iface->in_addrs)
if (n == iface->addrs) {
/* Just pick an IP number from our list */
ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->cfg.my_range.ipaddr);
ipcp->peer_ip = ChooseHisAddr(bundle, myaddr);
}
if (ipcp->peer_ip.s_addr == INADDR_ANY) {
*dec->rejend++ = TY_IPADDR;
@ -1104,23 +997,21 @@ ipcp_ValidateReq(struct ipcp *ipcp, struct in_addr ip, struct fsm_decode *dec)
}
return;
}
} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ip)) {
} else if (!ncprange_containsip4(&ipcp->cfg.peer_range, ip)) {
/*
* If the destination address is not acceptable, NAK with what we
* want to use.
*/
*dec->nakend++ = TY_IPADDR;
*dec->nakend++ = 6;
for (n = 0; n < iface->in_addrs; n++)
if ((iface->in_addr[n].brd.s_addr & ipcp->cfg.peer_range.mask.s_addr)
== (ipcp->cfg.peer_range.ipaddr.s_addr &
ipcp->cfg.peer_range.mask.s_addr)) {
for (n = 0; n < iface->addrs; n++)
if (ncprange_contains(&ipcp->cfg.peer_range, &iface->addr[n].peer)) {
/* We prefer the already-configured address */
memcpy(dec->nakend, &iface->in_addr[n].brd.s_addr, 4);
ncpaddr_getip4addr(&iface->addr[n].peer, (u_int32_t *)dec->nakend);
break;
}
if (n == iface->in_addrs)
if (n == iface->addrs)
memcpy(dec->nakend, &ipcp->peer_ip.s_addr, 4);
dec->nakend += 4;
@ -1139,6 +1030,7 @@ IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
struct fsm_decode *dec)
{
/* Deal with incoming PROTO_IPCP */
struct ncpaddr ncpaddr;
struct ipcp *ipcp = fsm2ipcp(fp);
int type, length, gotdnsnak;
u_int32_t compproto;
@ -1171,13 +1063,14 @@ IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
break;
case MODE_NAK:
if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
if (ncprange_containsip4(&ipcp->cfg.my_range, ipaddr)) {
/* Use address suggested by peer */
snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
inet_ntoa(ipcp->my_ip));
log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
ipcp->my_ip = ipaddr;
bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL);
ncpaddr_setip4(&ncpaddr, ipcp->my_ip);
bundle_AdjustFilters(fp->bundle, &ncpaddr, NULL);
} else {
log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
"%s: Unacceptable address!\n", inet_ntoa(ipaddr));
@ -1307,14 +1200,14 @@ IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
dec->rejend += length;
break;
}
have_ip = ipcp->dns[type == TY_PRIMARY_DNS ? 0 : 1];
have_ip = ipcp->ns.dns[type == TY_PRIMARY_DNS ? 0 : 1];
if (type == TY_PRIMARY_DNS && ipaddr.s_addr != have_ip.s_addr &&
ipaddr.s_addr == ipcp->dns[1].s_addr) {
ipaddr.s_addr == ipcp->ns.dns[1].s_addr) {
/* Swap 'em 'round */
ipcp->dns[0] = ipcp->dns[1];
ipcp->dns[1] = have_ip;
have_ip = ipcp->dns[0];
ipcp->ns.dns[0] = ipcp->ns.dns[1];
ipcp->ns.dns[1] = have_ip;
have_ip = ipcp->ns.dns[0];
}
if (ipaddr.s_addr != have_ip.s_addr) {
@ -1338,7 +1231,8 @@ IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
case MODE_NAK:
if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
gotdnsnak = 1;
memcpy(&ipcp->dns[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);
memcpy(&ipcp->ns.dns[type == TY_PRIMARY_DNS ? 0 : 1].s_addr,
cp + 2, 4);
}
break;
@ -1399,17 +1293,16 @@ IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
}
if (gotdnsnak) {
memcpy(ipcp->ns.dns, ipcp->dns, sizeof ipcp->ns.dns);
if (ipcp->ns.writable) {
log_Printf(LogDEBUG, "Updating resolver\n");
if (!ipcp_WriteDNS(ipcp)) {
ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
} else
bundle_AdjustDNS(fp->bundle, ipcp->dns);
bundle_AdjustDNS(fp->bundle);
} else {
log_Printf(LogDEBUG, "Not updating resolver (readonly)\n");
bundle_AdjustDNS(fp->bundle, ipcp->dns);
bundle_AdjustDNS(fp->bundle);
}
}
@ -1458,23 +1351,24 @@ int
ipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
{
struct ipcp *ipcp = &bundle->ncp.ipcp;
struct in_addr myaddr;
memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
iplist_reset(&ipcp->cfg.peer_list);
ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr;
ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
ipcp->cfg.peer_range.width = 32;
ipcp->peer_ip = hisaddr;
ncprange_setip4host(&ipcp->cfg.peer_range, hisaddr);
ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0)
return 0;
return 1; /* Ok */
return ipcp_SetIPaddress(ipcp, myaddr, hisaddr);
}
int
ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
{
struct ipcp *ipcp = &bundle->ncp.ipcp;
struct in_addr myaddr;
struct ncp *ncp = &bundle->ncp;
struct ipcp *ipcp = &ncp->ipcp;
struct ncpaddr ncpaddr;
/* Use `hisaddr' for the peers address (set iface if `setaddr') */
memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
@ -1488,25 +1382,26 @@ ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
return 0;
}
ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
ipcp->cfg.peer_range.width = 32;
ncprange_setip4host(&ipcp->cfg.peer_range, ipcp->peer_ip);
} else {
log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
return 0;
}
} else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr,
&ipcp->cfg.peer_range.mask,
&ipcp->cfg.peer_range.width) != 0) {
ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
} else if (ncprange_aton(&ipcp->cfg.peer_range, ncp, hisaddr) != 0) {
if (ncprange_family(&ipcp->cfg.my_range) != AF_INET) {
log_Printf(LogWARN, "%s: Not an AF_INET address !\n", hisaddr);
return 0;
}
ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip);
if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
ipcp->cfg.peer_range.ipaddr, 0) < 0)
if (setaddr && !ipcp_SetIPaddress(ipcp, myaddr, ipcp->peer_ip))
return 0;
} else
return 0;
bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip);
ncpaddr_setip4(&ncpaddr, ipcp->peer_ip);
bundle_AdjustFilters(bundle, NULL, &ncpaddr);
return 1; /* Ok */
}
@ -1523,3 +1418,59 @@ addr2mask(struct in_addr addr)
return addr;
}
size_t
ipcp_QueueLen(struct ipcp *ipcp)
{
struct mqueue *q;
size_t result;
result = 0;
for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
result += q->len;
return result;
}
int
ipcp_PushPacket(struct ipcp *ipcp, struct link *l)
{
struct bundle *bundle = ipcp->fsm.bundle;
struct mqueue *queue;
struct mbuf *bp;
int m_len;
u_int32_t secs = 0;
unsigned alivesecs = 0;
if (ipcp->fsm.state != ST_OPENED)
return 0;
/*
* If ccp is not open but is required, do nothing.
*/
if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
return 0;
}
queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
do {
if (queue->top) {
bp = m_dequeue(queue);
bp = mbuf_Read(bp, &secs, sizeof secs);
bp = m_pullup(bp);
m_len = m_length(bp);
if (!FilterCheck(MBUF_CTOP(bp), AF_INET, &bundle->filter.alive,
&alivesecs)) {
if (secs == 0)
secs = alivesecs;
bundle_StartIdleTimer(bundle, secs);
}
link_PushPacket(l, bp, bundle, 0, PROTO_IP);
ipcp_AddOutOctets(ipcp, m_len);
return 1;
}
} while (queue-- != ipcp->Queue);
return 0;
}

View File

@ -42,20 +42,6 @@
#define TY_SECONDARY_NBNS 132
#define TY_ADJUST_NS 119 /* subtract from NS val for REJECT bit */
struct sticky_route;
struct in_range {
struct in_addr ipaddr;
struct in_addr mask;
int width;
};
struct port_range {
unsigned nports; /* How many ports */
unsigned maxports; /* How many allocated (malloc) ports */
u_short *port; /* The actual ports */
};
struct ipcp {
struct fsm fsm; /* The finite state machine */
@ -66,14 +52,11 @@ struct ipcp {
unsigned neg : 2; /* VJ negotiation */
} vj;
struct in_range my_range; /* MYADDR spec */
struct ncprange my_range; /* MYADDR spec */
struct in_addr netmask; /* Iface netmask (unused by most OSs) */
struct in_range peer_range; /* HISADDR spec */
struct ncprange peer_range; /* HISADDR spec */
struct iplist peer_list; /* Ranges of HISADDR values */
u_long sendpipe; /* route sendpipe size */
u_long recvpipe; /* route recvpipe size */
struct in_addr TriggerAddress; /* Address to suggest in REQ */
unsigned HaveTriggerAddress : 1; /* Trigger address specified */
@ -83,12 +66,7 @@ struct ipcp {
struct in_addr nbns[2]; /* NetBIOS NS addresses offered */
} ns;
struct {
struct port_range tcp, udp; /* The range of urgent ports */
unsigned tos : 1; /* Urgent IPTOS_LOWDELAY packets ? */
} urgent;
struct fsm_retry fsm; /* How often/frequently to resend requests */
struct fsm_retry fsm; /* frequency to resend requests */
} cfg;
struct {
@ -104,8 +82,6 @@ struct ipcp {
char *resolv_nons; /* Contents of resolv.conf without ns */
} ns;
struct sticky_route *route; /* List of dynamic routes */
unsigned heis1172 : 1; /* True if he is speaking rfc1172 */
unsigned peer_req : 1; /* Any TY_IPADDR REQs from the peer ? */
@ -117,8 +93,6 @@ struct ipcp {
struct in_addr my_ip; /* IP address I'm willing to use */
u_int32_t my_compproto; /* VJ params I'm willing to use */
struct in_addr dns[2]; /* DNSs to REQ/ACK */
u_int32_t peer_reject; /* Request codes rejected by peer */
u_int32_t my_reject; /* Request codes I have rejected */
@ -132,6 +106,7 @@ struct ipcp {
struct bundle;
struct link;
struct cmdargs;
struct iface_addr;
extern void ipcp_Init(struct ipcp *, struct bundle *, struct link *,
const struct fsm_parent *);
@ -146,32 +121,12 @@ extern void ipcp_AddOutOctets(struct ipcp *, int);
extern int ipcp_UseHisIPaddr(struct bundle *, struct in_addr);
extern int ipcp_UseHisaddr(struct bundle *, const char *, int);
extern int ipcp_vjset(struct cmdargs const *);
extern void ipcp_CleanInterface(struct ipcp *);
extern void ipcp_IfaceAddrAdded(struct ipcp *, const struct iface_addr *);
extern void ipcp_IfaceAddrDeleted(struct ipcp *, const struct iface_addr *);
extern int ipcp_InterfaceUp(struct ipcp *);
extern int ipcp_IsUrgentPort(struct port_range *, u_short, u_short);
extern void ipcp_AddUrgentPort(struct port_range *, u_short);
extern void ipcp_RemoveUrgentPort(struct port_range *, u_short);
extern void ipcp_ClearUrgentPorts(struct port_range *);
extern struct in_addr addr2mask(struct in_addr);
extern int ipcp_WriteDNS(struct ipcp *);
extern void ipcp_RestoreDNS(struct ipcp *);
extern void ipcp_LoadDNS(struct ipcp *);
#define ipcp_IsUrgentTcpPort(ipcp, p1, p2) \
ipcp_IsUrgentPort(&(ipcp)->cfg.urgent.tcp, p1, p2)
#define ipcp_IsUrgentUdpPort(ipcp, p1, p2) \
ipcp_IsUrgentPort(&(ipcp)->cfg.urgent.udp, p1, p2)
#define ipcp_AddUrgentTcpPort(ipcp, p) \
ipcp_AddUrgentPort(&(ipcp)->cfg.urgent.tcp, p)
#define ipcp_AddUrgentUdpPort(ipcp, p) \
ipcp_AddUrgentPort(&(ipcp)->cfg.urgent.udp, p)
#define ipcp_RemoveUrgentTcpPort(ipcp, p) \
ipcp_RemoveUrgentPort(&(ipcp)->cfg.urgent.tcp, p)
#define ipcp_RemoveUrgentUdpPort(ipcp, p) \
ipcp_RemoveUrgentPort(&(ipcp)->cfg.urgent.udp, p)
#define ipcp_ClearUrgentTcpPorts(ipcp) \
ipcp_ClearUrgentPorts(&(ipcp)->cfg.urgent.tcp)
#define ipcp_ClearUrgentUdpPorts(ipcp) \
ipcp_ClearUrgentPorts(&(ipcp)->cfg.urgent.udp)
#define ipcp_ClearUrgentTOS(ipcp) (ipcp)->cfg.urgent.tos = 0;
#define ipcp_SetUrgentTOS(ipcp) (ipcp)->cfg.urgent.tos = 1;
extern size_t ipcp_QueueLen(struct ipcp *);
extern int ipcp_PushPacket(struct ipcp *, struct link *);

601
usr.sbin/ppp/ipv6cp.c Normal file
View File

@ -0,0 +1,601 @@
/*-
* Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <net/route.h>
#include <net/if.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include "layer.h"
#include "defs.h"
#include "mbuf.h"
#include "timer.h"
#include "fsm.h"
#include "iplist.h"
#include "throughput.h"
#include "slcompress.h"
#include "lqr.h"
#include "hdlc.h"
#include "lcp.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "ipv6cp.h"
#include "filter.h"
#include "descriptor.h"
#include "ccp.h"
#include "link.h"
#include "mp.h"
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ncp.h"
#include "bundle.h"
#include "route.h"
#include "iface.h"
#include "log.h"
#include "proto.h"
#include "command.h"
#include "prompt.h"
#include "async.h"
#include "physical.h"
#ifndef NOINET6
static int ipv6cp_LayerUp(struct fsm *);
static void ipv6cp_LayerDown(struct fsm *);
static void ipv6cp_LayerStart(struct fsm *);
static void ipv6cp_LayerFinish(struct fsm *);
static void ipv6cp_InitRestartCounter(struct fsm *, int);
static void ipv6cp_SendConfigReq(struct fsm *);
static void ipv6cp_SentTerminateReq(struct fsm *);
static void ipv6cp_SendTerminateAck(struct fsm *, u_char);
static void ipv6cp_DecodeConfig(struct fsm *, u_char *, int, int,
struct fsm_decode *);
static struct fsm_callbacks ipv6cp_Callbacks = {
ipv6cp_LayerUp,
ipv6cp_LayerDown,
ipv6cp_LayerStart,
ipv6cp_LayerFinish,
ipv6cp_InitRestartCounter,
ipv6cp_SendConfigReq,
ipv6cp_SentTerminateReq,
ipv6cp_SendTerminateAck,
ipv6cp_DecodeConfig,
fsm_NullRecvResetReq,
fsm_NullRecvResetAck
};
static u_int32_t
GenerateToken(void)
{
/* Generate random number which will be used as negotiation token */
randinit();
return random() + 1;
}
static int
ipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_int32_t mytok, u_int32_t histok)
{
struct bundle *bundle = ipv6cp->fsm.bundle;
struct in6_addr myaddr, hisaddr;
struct ncprange myrange, dst;
memset(&myaddr, '\0', sizeof myaddr);
memset(&hisaddr, '\0', sizeof hisaddr);
myaddr.s6_addr[0] = 0xfe;
myaddr.s6_addr[1] = 0x80;
*(u_int32_t *)(myaddr.s6_addr + 12) = htonl(mytok);
hisaddr.s6_addr[0] = 0xfe;
hisaddr.s6_addr[1] = 0x80;
*(u_int32_t *)(hisaddr.s6_addr + 12) = htonl(histok);
ncpaddr_setip6(&ipv6cp->myaddr, &myaddr);
ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr);
ncprange_sethost(&myrange, &ipv6cp->myaddr);
if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr,
IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
return 0;
if (!Enabled(bundle, OPT_IFACEALIAS))
iface_Clear(bundle->iface, &bundle->ncp, AF_INET6,
IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
ncprange_sethost(&dst, &ipv6cp->hisaddr);
rt_Update(bundle, &dst);
}
if (Enabled(bundle, OPT_SROUTES))
route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr);
#ifndef NORADIUS
if (bundle->radius.valid)
route_Change(bundle, bundle->radius.routes, &ipv6cp->myaddr,
&ipv6cp->hisaddr);
#endif
return 1; /* Ok */
}
void
ipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l,
const struct fsm_parent *parent)
{
static const char * const timer_names[] =
{"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"};
int n;
fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP,
bundle, l, parent, &ipv6cp_Callbacks, timer_names);
ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY;
ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES;
ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES;
ipv6cp->my_token = GenerateToken();
while ((ipv6cp->peer_token = GenerateToken()) == ipv6cp->my_token)
;
n = 100;
while (n &&
!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_token, ipv6cp->peer_token))
while (n && (ipv6cp->my_token = GenerateToken()) == ipv6cp->peer_token)
n--;
throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD);
memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue);
ipv6cp_Setup(ipv6cp);
}
void
ipv6cp_Destroy(struct ipv6cp *ipv6cp)
{
throughput_destroy(&ipv6cp->throughput);
}
void
ipv6cp_Setup(struct ipv6cp *ipv6cp)
{
ncpaddr_init(&ipv6cp->myaddr);
ncpaddr_init(&ipv6cp->hisaddr);
ipv6cp->his_reject = 0;
ipv6cp->my_reject = 0;
}
void
ipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l)
{
ipv6cp->fsm.link = l;
}
int
ipv6cp_Show(struct cmdargs const *arg)
{
struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp;
prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name,
State2Nam(ipv6cp->fsm.state));
if (ipv6cp->fsm.state == ST_OPENED) {
prompt_Printf(arg->prompt, " His side: %s\n",
ncpaddr_ntoa(&ipv6cp->hisaddr));
prompt_Printf(arg->prompt, " My side: %s\n",
ncpaddr_ntoa(&ipv6cp->myaddr));
prompt_Printf(arg->prompt, " Queued packets: %lu\n",
(unsigned long)ipv6cp_QueueLen(ipv6cp));
}
prompt_Printf(arg->prompt, "\nDefaults:\n");
prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
" REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout,
ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s",
ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s");
throughput_disp(&ipv6cp->throughput, arg->prompt);
return 0;
}
struct mbuf *
ipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
{
/* Got PROTO_IPV6CP from link */
m_settype(bp, MB_IPV6CPIN);
if (bundle_Phase(bundle) == PHASE_NETWORK)
fsm_Input(&bundle->ncp.ipv6cp.fsm, bp);
else {
if (bundle_Phase(bundle) < PHASE_NETWORK)
log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s"
" (ignored)\n", l->name, bundle_PhaseName(bundle));
m_freem(bp);
}
return NULL;
}
void
ipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n)
{
throughput_addin(&ipv6cp->throughput, n);
}
void
ipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n)
{
throughput_addout(&ipv6cp->throughput, n);
}
void
ipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp, const struct iface_addr *addr)
{
}
void
ipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp, const struct iface_addr *addr)
{
}
int
ipv6cp_InterfaceUp(struct ipv6cp *ipv6cp)
{
if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_token, ipv6cp->peer_token)) {
log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n");
return 0;
}
if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) {
log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP"
" flag on %s\n", ipv6cp->fsm.bundle->iface->name);
return 0;
}
return 1;
}
size_t
ipv6cp_QueueLen(struct ipv6cp *ipv6cp)
{
struct mqueue *q;
size_t result;
result = 0;
for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
result += q->len;
return result;
}
int
ipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l)
{
struct bundle *bundle = ipv6cp->fsm.bundle;
struct mqueue *queue;
struct mbuf *bp;
int m_len;
u_int32_t secs = 0;
unsigned alivesecs = 0;
if (ipv6cp->fsm.state != ST_OPENED)
return 0;
/*
* If ccp is not open but is required, do nothing.
*/
if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
return 0;
}
queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1;
do {
if (queue->top) {
bp = m_dequeue(queue);
bp = mbuf_Read(bp, &secs, sizeof secs);
bp = m_pullup(bp);
m_len = m_length(bp);
if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive,
&alivesecs)) {
if (secs == 0)
secs = alivesecs;
bundle_StartIdleTimer(bundle, secs);
}
link_PushPacket(l, bp, bundle, 0, PROTO_IPV6);
ipv6cp_AddOutOctets(ipv6cp, m_len);
return 1;
}
} while (queue-- != ipv6cp->Queue);
return 0;
}
static int
ipv6cp_LayerUp(struct fsm *fp)
{
/* We're now up */
struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
char tbuff[40];
log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name);
if (!ipv6cp_InterfaceUp(ipv6cp))
return 0;
snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n",
tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr));
/* XXX: Call radius_Account() and system_Select() */
fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
log_DisplayPrompts();
return 1;
}
static void
ipv6cp_LayerDown(struct fsm *fp)
{
/* About to come down */
struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
static int recursing;
char addr[40];
if (!recursing++) {
snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr);
/* XXX: Call radius_Account() and system_Select() */
ipv6cp_Setup(ipv6cp);
}
recursing--;
}
static void
ipv6cp_LayerStart(struct fsm *fp)
{
/* We're about to start up ! */
struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name);
throughput_start(&ipv6cp->throughput, "IPV6CP throughput",
Enabled(fp->bundle, OPT_THROUGHPUT));
fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
ipv6cp->peer_tokenreq = 0;
}
static void
ipv6cp_LayerFinish(struct fsm *fp)
{
/* We're now down */
struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name);
throughput_stop(&ipv6cp->throughput);
throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL);
}
static void
ipv6cp_InitRestartCounter(struct fsm *fp, int what)
{
/* Set fsm timer load */
struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS;
switch (what) {
case FSM_REQ_TIMER:
fp->restart = ipv6cp->cfg.fsm.maxreq;
break;
case FSM_TRM_TIMER:
fp->restart = ipv6cp->cfg.fsm.maxtrm;
break;
default:
fp->restart = 1;
break;
}
}
static void
ipv6cp_SendConfigReq(struct fsm *fp)
{
/* Send config REQ please */
struct physical *p = link2physical(fp->link);
struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
u_char buff[6];
struct lcp_opt *o;
o = (struct lcp_opt *)buff;
if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) {
memcpy(o->data, &ipv6cp->my_token, 4);
INC_LCP_OPT(TY_TOKEN, 6, o);
}
fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
MB_IPV6CPOUT);
}
static void
ipv6cp_SentTerminateReq(struct fsm *fp)
{
/* Term REQ just sent by FSM */
}
static void
ipv6cp_SendTerminateAck(struct fsm *fp, u_char id)
{
/* Send Term ACK please */
fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT);
}
static const char *
protoname(int proto)
{
static const char *cftypes[] = { "TOKEN", "COMPPROTO" };
if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes)
return cftypes[proto - 1];
return NumStr(proto, NULL, 0);
}
static void
ipv6cp_ValidateToken(struct ipv6cp *ipv6cp, u_int32_t token,
struct fsm_decode *dec)
{
if (token != 0 && token != ipv6cp->my_token)
ipv6cp->peer_token = token;
if (token == ipv6cp->peer_token) {
*dec->ackend++ = TY_TOKEN;
*dec->ackend++ = 6;
memcpy(dec->ackend, &ipv6cp->peer_token, 4);
dec->ackend += 4;
} else {
*dec->nakend++ = TY_TOKEN;
*dec->nakend++ = 6;
memcpy(dec->nakend, &ipv6cp->peer_token, 4);
dec->nakend += 4;
}
}
static void
ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
struct fsm_decode *dec)
{
/* Deal with incoming PROTO_IPV6CP */
struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
int type, length, n;
char tbuff[100];
u_int32_t token;
while (plen >= sizeof(struct fsmconfig)) {
type = *cp;
length = cp[1];
if (length == 0) {
log_Printf(LogIPV6CP, "%s: IPV6CP size zero\n", fp->link->name);
break;
}
snprintf(tbuff, sizeof tbuff, " %s[%d] ", protoname(type), length);
switch (type) {
case TY_TOKEN:
memcpy(&token, cp + 2, 4);
log_Printf(LogIPV6CP, "%s 0x%08lx\n", tbuff, (unsigned long)token);
switch (mode_type) {
case MODE_REQ:
ipv6cp->peer_tokenreq = 1;
ipv6cp_ValidateToken(ipv6cp, token, dec);
break;
case MODE_NAK:
if (token == 0) {
log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
"0x00000000: Unacceptable token!\n");
fsm_Close(&ipv6cp->fsm);
} else if (token == ipv6cp->peer_token)
log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
"0x08lx: Unacceptable token!\n", (unsigned long)token);
else if (token != ipv6cp->my_token) {
n = 100;
while (n && !ipcp_SetIPv6address(ipv6cp, token, ipv6cp->peer_token))
while (n && (token = GenerateToken()) == ipv6cp->peer_token)
n--;
if (n == 0) {
log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
"0x00000000: Unacceptable token!\n");
fsm_Close(&ipv6cp->fsm);
} else {
log_Printf(LogIPV6CP, "%s changing token: 0x%08lx --> 0x%08lx\n",
tbuff, (unsigned long)ipv6cp->my_token,
(unsigned long)token);
ipv6cp->my_token = token;
bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL);
}
}
break;
case MODE_REJ:
ipv6cp->his_reject |= (1 << type);
break;
}
break;
default:
if (mode_type != MODE_NOP) {
ipv6cp->my_reject |= (1 << type);
memcpy(dec->rejend, cp, length);
dec->rejend += length;
}
break;
}
plen -= length;
cp += length;
}
if (mode_type != MODE_NOP) {
if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) {
if (dec->rejend == dec->rej && dec->nakend == dec->nak) {
/*
* Pretend the peer has requested a TOKEN.
* We do this to ensure that we only send one NAK if the only
* reason for the NAK is because the peer isn't sending a
* TY_TOKEN REQ. This stops us from repeatedly trying to tell
* the peer that we have to have an IP address on their end.
*/
ipv6cp->peer_tokenreq = 1;
}
ipv6cp_ValidateToken(ipv6cp, 0, dec);
}
if (dec->rejend != dec->rej) {
/* rejects are preferred */
dec->ackend = dec->ack;
dec->nakend = dec->nak;
} else if (dec->nakend != dec->nak)
/* then NAKs */
dec->ackend = dec->ack;
}
}
#endif

81
usr.sbin/ppp/ipv6cp.h Normal file
View File

@ -0,0 +1,81 @@
/*-
* Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef NOINET6
#define IPV6CP_MAXCODE CODE_CODEREJ
#define TY_TOKEN 1
#define TY_COMPPROTO 2
struct ipv6cp {
struct fsm fsm; /* The finite state machine */
struct {
struct fsm_retry fsm; /* frequency to resend requests */
} cfg;
unsigned peer_tokenreq : 1; /* Any TY_TOKEN REQs from the peer ? */
u_int32_t my_token; /* Token I'm willing to use */
u_int32_t peer_token; /* Token he's willing to use */
struct ncpaddr myaddr; /* Local address */
struct ncpaddr hisaddr; /* Peer address */
u_int32_t his_reject; /* Request codes rejected by peer */
u_int32_t my_reject; /* Request codes I have rejected */
struct pppThroughput throughput; /* throughput statistics */
struct mqueue Queue[2]; /* Output packet queues */
};
#define fsm2ipv6cp(fp) (fp->proto == PROTO_IPV6CP ? (struct ipv6cp *)fp : NULL)
#define IPV6CP_QUEUES(ipv6cp) (sizeof ipv6cp->Queue / sizeof ipv6cp->Queue[0])
struct bundle;
struct link;
struct cmdargs;
struct iface_addr;
extern void ipv6cp_Init(struct ipv6cp *, struct bundle *, struct link *,
const struct fsm_parent *);
extern void ipv6cp_Destroy(struct ipv6cp *);
extern void ipv6cp_Setup(struct ipv6cp *);
extern void ipv6cp_SetLink(struct ipv6cp *, struct link *);
extern int ipv6cp_Show(struct cmdargs const *);
extern struct mbuf *ipv6cp_Input(struct bundle *, struct link *, struct mbuf *);
extern void ipv6cp_AddInOctets(struct ipv6cp *, int);
extern void ipv6cp_AddOutOctets(struct ipv6cp *, int);
extern void ipv6cp_IfaceAddrAdded(struct ipv6cp *, const struct iface_addr *);
extern void ipv6cp_IfaceAddrDeleted(struct ipv6cp *, const struct iface_addr *);
extern int ipv6cp_InterfaceUp(struct ipv6cp *);
extern size_t ipv6cp_QueueLen(struct ipv6cp *);
extern int ipv6cp_PushPacket(struct ipv6cp *, struct link *);
#endif

View File

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
@ -62,6 +63,8 @@
#include "physical.h"
#include "prompt.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "mp.h"
@ -73,6 +76,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
/* for received LQRs */

View File

@ -29,6 +29,7 @@
#include <sys/types.h>
#include <netinet/in_systm.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/ip.h>
@ -57,8 +58,10 @@
#include "mp.h"
#include "iplist.h"
#include "slcompress.h"
#include "ipcp.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "ipv6cp.h"
#include "auth.h"
#include "pap.h"
#include "chap.h"
@ -317,10 +320,16 @@ static const struct {
u_short proto;
struct mbuf *(*fn)(struct bundle *, struct link *, struct mbuf *);
} despatcher[] = {
{ PROTO_IP, ip_Input },
{ PROTO_IP, ipv4_Input },
#ifndef NOINET6
{ PROTO_IPV6, ipv6_Input },
#endif
{ PROTO_MP, mp_Input },
{ PROTO_LCP, lcp_Input },
{ PROTO_IPCP, ipcp_Input },
#ifndef NOINET6
{ PROTO_IPV6CP, ipv6cp_Input },
#endif
{ PROTO_PAP, pap_Input },
{ PROTO_CHAP, chap_Input },
{ PROTO_CCP, ccp_Input },

View File

@ -42,7 +42,7 @@
#include "descriptor.h"
#include "prompt.h"
static const char * const LogNames[] = {
static const char *const LogNames[] = {
"Async",
"CBCP",
"CCP",
@ -55,6 +55,7 @@ static const char * const LogNames[] = {
"HDLC",
"ID0",
"IPCP",
"IPV6CP",
"LCP",
"LQM",
"Phase",

View File

@ -39,20 +39,21 @@
#define LogHDLC (10)
#define LogID0 (11)
#define LogIPCP (12)
#define LogLCP (13)
#define LogLQM (14)
#define LogPHASE (15)
#define LogPHYSICAL (16) /* syslog(LOG_INFO, ....) */
#define LogSYNC (17) /* syslog(LOG_INFO, ....) */
#define LogTCPIP (18)
#define LogTIMER (19) /* syslog(LOG_DEBUG, ....) */
#define LogTUN (20) /* If set, tun%d is output with each message */
#define LogWARN (21) /* Sent to VarTerm else syslog(LOG_WARNING, ) */
#define LogERROR (22) /* syslog(LOG_ERR, ....), + sent to VarTerm */
#define LogALERT (23) /* syslog(LOG_ALERT, ....) */
#define LogIPV6CP (13)
#define LogLCP (14)
#define LogLQM (15)
#define LogPHASE (16)
#define LogPHYSICAL (17) /* syslog(LOG_INFO, ....) */
#define LogSYNC (18) /* syslog(LOG_INFO, ....) */
#define LogTCPIP (19)
#define LogTIMER (20) /* syslog(LOG_DEBUG, ....) */
#define LogTUN (21) /* If set, tun%d is output with each message */
#define LogWARN (22) /* Sent to VarTerm else syslog(LOG_WARNING, ) */
#define LogERROR (23) /* syslog(LOG_ERR, ....), + sent to VarTerm */
#define LogALERT (24) /* syslog(LOG_ALERT, ....) */
#define LogMAXCONF (20)
#define LogMAX (23)
#define LogMAXCONF (21)
#define LogMAX (24)
struct mbuf;
struct cmdargs;

View File

@ -71,6 +71,8 @@
#include "iplist.h"
#include "throughput.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -79,6 +81,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "auth.h"
#include "systems.h"
@ -413,7 +417,7 @@ main(int argc, char **argv)
bundle_SetLabel(bundle, lastlabel);
if (sw.mode == PHYS_AUTO &&
bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) {
prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address "
"in auto mode.\n");
AbortProgram(EX_START);

View File

@ -87,13 +87,13 @@ static const char *
mbuftype(int type)
{
static const char * const mbufdesc[MB_MAX] = {
"ip in", "ip out", "nat in", "nat out", "mp in", "mp out",
"vj in", "vj out", "icompd in", "icompd out", "compd in", "compd out",
"lqr in", "lqr out", "echo in", "echo out", "proto in", "proto out",
"acf in", "acf out", "sync in", "sync out", "hdlc in", "hdlc out",
"async in", "async out", "cbcp in", "cbcp out", "chap in", "chap out",
"pap in", "pap out", "ccp in", "ccp out", "ipcp in", "ipcp out",
"lcp in", "lcp out"
"ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out",
"mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out",
"compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out",
"proto in", "proto out", "acf in", "acf out", "sync in", "sync out",
"hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out",
"chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out",
"ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out"
};
return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type];

View File

@ -52,43 +52,47 @@ struct mqueue {
#define MB_IPIN 0
#define MB_IPOUT 1
#define MB_NATIN 2
#define MB_NATOUT 3
#define MB_MPIN 4
#define MB_MPOUT 5
#define MB_VJIN 6
#define MB_VJOUT 7
#define MB_ICOMPDIN 8
#define MB_ICOMPDOUT 9
#define MB_COMPDIN 10
#define MB_COMPDOUT 11
#define MB_LQRIN 12
#define MB_LQROUT 13
#define MB_ECHOIN 14
#define MB_ECHOOUT 15
#define MB_PROTOIN 16
#define MB_PROTOOUT 17
#define MB_ACFIN 18
#define MB_ACFOUT 19
#define MB_SYNCIN 20
#define MB_SYNCOUT 21
#define MB_HDLCIN 22
#define MB_HDLCOUT 23
#define MB_ASYNCIN 24
#define MB_ASYNCOUT 25
#define MB_CBCPIN 26
#define MB_CBCPOUT 27
#define MB_CHAPIN 28
#define MB_CHAPOUT 29
#define MB_PAPIN 30
#define MB_PAPOUT 31
#define MB_CCPIN 32
#define MB_CCPOUT 33
#define MB_IPCPIN 34
#define MB_IPCPOUT 35
#define MB_LCPIN 36
#define MB_LCPOUT 37
#define MB_UNKNOWN 38
#define MB_IPV6IN 2
#define MB_IPV6OUT 3
#define MB_NATIN 4
#define MB_NATOUT 5
#define MB_MPIN 6
#define MB_MPOUT 7
#define MB_VJIN 8
#define MB_VJOUT 9
#define MB_ICOMPDIN 10
#define MB_ICOMPDOUT 11
#define MB_COMPDIN 12
#define MB_COMPDOUT 13
#define MB_LQRIN 14
#define MB_LQROUT 15
#define MB_ECHOIN 16
#define MB_ECHOOUT 17
#define MB_PROTOIN 18
#define MB_PROTOOUT 19
#define MB_ACFIN 20
#define MB_ACFOUT 21
#define MB_SYNCIN 22
#define MB_SYNCOUT 23
#define MB_HDLCIN 24
#define MB_HDLCOUT 25
#define MB_ASYNCIN 26
#define MB_ASYNCOUT 27
#define MB_CBCPIN 28
#define MB_CBCPOUT 29
#define MB_CHAPIN 30
#define MB_CHAPOUT 31
#define MB_PAPIN 32
#define MB_PAPOUT 33
#define MB_CCPIN 34
#define MB_CCPOUT 35
#define MB_IPCPIN 36
#define MB_IPCPOUT 37
#define MB_IPV6CPIN 38
#define MB_IPV6CPOUT 39
#define MB_LCPIN 40
#define MB_LCPOUT 41
#define MB_UNKNOWN 42
#define MB_MAX MB_UNKNOWN
#define M_MAXLEN (4352 - sizeof(struct mbuf)) /* > HDLCSIZE */

View File

@ -61,6 +61,8 @@
#include "slcompress.h"
#include "lqr.h"
#include "hdlc.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "auth.h"
#include "lcp.h"
@ -79,8 +81,9 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "ip.h"
#include "prompt.h"
#include "id.h"
#include "arp.h"
@ -243,6 +246,7 @@ mp_Init(struct mp *mp, struct bundle *bundle)
mp->out.seq = 0;
mp->out.link = 0;
mp->out.af = AF_INET;
mp->seq.min_in = 0;
mp->seq.next_in = 0;
mp->inbufs = NULL;
@ -336,6 +340,7 @@ mp_Up(struct mp *mp, struct datalink *dl)
mp->out.seq = 0;
mp->out.link = 0;
mp->out.af = AF_INET;
mp->seq.min_in = 0;
mp->seq.next_in = 0;
@ -355,8 +360,8 @@ mp_Up(struct mp *mp, struct datalink *dl)
log_Printf(LogPHASE, "mp: Listening on %s\n", mp->server.socket.sun_path);
log_Printf(LogPHASE, " First link: %s\n", dl->name);
/* Re-point our IPCP layer at our MP link */
ipcp_SetLink(&mp->bundle->ncp.ipcp, &mp->link);
/* Re-point our NCP layers at our MP link */
ncp_SetLink(&mp->bundle->ncp, &mp->link);
/* Our lcp's already up 'cos of the NULL parent */
if (ccp_SetOpenMode(&mp->link.ccp)) {
@ -657,7 +662,7 @@ mp_Output(struct mp *mp, struct bundle *bundle, struct link *l,
}
int
mp_FillQueues(struct bundle *bundle)
mp_FillPhysicalQueues(struct bundle *bundle)
{
struct mp *mp = &bundle->ncp.mp;
struct datalink *dl, *fdl;
@ -665,6 +670,7 @@ mp_FillQueues(struct bundle *bundle)
int thislink, nlinks;
u_int32_t begin, end;
struct mbuf *m, *mo;
struct link *bestlink;
thislink = nlinks = 0;
for (fdl = NULL, dl = bundle->links; dl; dl = dl->next) {
@ -706,7 +712,7 @@ mp_FillQueues(struct bundle *bundle)
continue;
}
if (!link_QueueLen(&mp->link)) {
if (!mp_QueueLen(mp)) {
struct datalink *other;
int mrutoosmall;
@ -714,7 +720,8 @@ mp_FillQueues(struct bundle *bundle)
* If there's only a single open link in our bundle and we haven't got
* MP level link compression, queue outbound traffic directly via that
* link's protocol stack rather than using the MP link. This results
* in the outbound traffic going out as PROTO_IP rather than PROTO_MP.
* in the outbound traffic going out as PROTO_IP or PROTO_IPV6 rather
* than PROTO_MP.
*/
for (other = dl->next; other; other = other->next)
if (other->state == DATALINK_OPEN)
@ -734,9 +741,9 @@ mp_FillQueues(struct bundle *bundle)
}
}
if (!ip_PushPacket(other ? &mp->link : &dl->physical->link, bundle))
/* Nothing else to send */
break;
bestlink = other ? &mp->link : &dl->physical->link;
if (!ncp_PushPacket(&bundle->ncp, &mp->out.af, bestlink))
break; /* Nothing else to send */
if (mrutoosmall)
log_Printf(LogDEBUG, "Don't send data as PROTO_IP, MRU < MRRU\n");
@ -978,7 +985,7 @@ mp_SetEnddisc(struct cmdargs const *arg)
mp->cfg.enddisc.len = strlen(mp->cfg.enddisc.address);
} else if (!strcasecmp(arg->argv[arg->argn], "ip")) {
if (arg->bundle->ncp.ipcp.my_ip.s_addr == INADDR_ANY)
addr = arg->bundle->ncp.ipcp.cfg.my_range.ipaddr;
ncprange_getip4addr(&arg->bundle->ncp.ipcp.cfg.my_range, &addr);
else
addr = arg->bundle->ncp.ipcp.my_ip;
memcpy(mp->cfg.enddisc.address, &addr.s_addr, sizeof addr.s_addr);
@ -989,7 +996,7 @@ mp_SetEnddisc(struct cmdargs const *arg)
int s;
if (arg->bundle->ncp.ipcp.my_ip.s_addr == INADDR_ANY)
addr = arg->bundle->ncp.ipcp.cfg.my_range.ipaddr;
ncprange_getip4addr(&arg->bundle->ncp.ipcp.cfg.my_range, &addr);
else
addr = arg->bundle->ncp.ipcp.my_ip;
@ -1195,8 +1202,8 @@ mp_LinkLost(struct mp *mp, struct datalink *dl)
mp_Assemble(mp, NULL, NULL);
}
void
mp_DeleteQueue(struct mp *mp)
size_t
mp_QueueLen(struct mp *mp)
{
link_DeleteQueue(&mp->link);
return link_QueueLen(&mp->link);
}

View File

@ -84,6 +84,7 @@ struct mp {
struct {
u_int32_t seq; /* next outgoing seq */
int link; /* Next link to send on */
int af; /* Next address family to send */
} out;
struct {
@ -133,13 +134,13 @@ extern void mp_linkInit(struct mp_link *);
extern int mp_Up(struct mp *, struct datalink *);
extern void mp_Down(struct mp *);
extern struct mbuf *mp_Input(struct bundle *, struct link *, struct mbuf *);
extern int mp_FillQueues(struct bundle *);
extern int mp_FillPhysicalQueues(struct bundle *);
extern int mp_SetDatalinkBandwidth(struct cmdargs const *);
extern int mp_ShowStatus(struct cmdargs const *);
extern const char *mp_Enddisc(u_char, const char *, int);
extern int mp_SetEnddisc(struct cmdargs const *);
extern void mp_LinkLost(struct mp *, struct datalink *);
extern void mp_DeleteQueue(struct mp *);
extern void mp_RestartAutoloadTimer(struct mp *);
extern void mp_CheckAutoloadTimer(struct mp *);
extern void mp_StopAutoloadTimer(struct mp *);
extern size_t mp_QueueLen(struct mp *);

View File

@ -34,6 +34,7 @@
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
@ -63,7 +64,10 @@
#include "mbuf.h"
#include "lqr.h"
#include "hdlc.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "ipv6cp.h"
#include "lcp.h"
#include "ccp.h"
#include "link.h"
@ -72,7 +76,7 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ip.h"
#include "ncp.h"
#include "bundle.h"
@ -547,7 +551,8 @@ nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp,
bp = NULL;
} else if (log_IsKept(LogTCPIP)) {
log_Printf(LogTCPIP, "NAT engine ignored data:\n");
PacketCheck(bundle, MBUF_CTOP(bp), bp->m_len, NULL, NULL, NULL);
PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL,
NULL, NULL);
}
break;

550
usr.sbin/ppp/ncp.c Normal file
View File

@ -0,0 +1,550 @@
/*-
* Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/route.h>
#include <netdb.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include "layer.h"
#include "ua.h"
#include "defs.h"
#include "command.h"
#include "mbuf.h"
#include "log.h"
#include "timer.h"
#include "fsm.h"
#include "proto.h"
#include "iplist.h"
#include "throughput.h"
#include "slcompress.h"
#include "lqr.h"
#include "hdlc.h"
#include "lcp.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
#include "vjcomp.h"
#include "async.h"
#include "ccp.h"
#include "link.h"
#include "physical.h"
#include "mp.h"
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "id.h"
#include "arp.h"
#include "systems.h"
#include "prompt.h"
#include "route.h"
#include "iface.h"
#include "chat.h"
#include "auth.h"
#include "chap.h"
#include "pap.h"
#include "cbcp.h"
#include "datalink.h"
static u_short default_urgent_tcp_ports[] = {
21, /* ftp */
22, /* ssh */
23, /* telnet */
513, /* login */
514, /* shell */
543, /* klogin */
544 /* kshell */
};
static u_short default_urgent_udp_ports[] = { };
#define NDEFTCPPORTS \
(sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0])
#define NDEFUDPPORTS \
(sizeof default_urgent_udp_ports / sizeof default_urgent_udp_ports[0])
void
ncp_Init(struct ncp *ncp, struct bundle *bundle)
{
ncp->afq = AF_INET;
ncp->route = NULL;
ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
ncp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
memcpy(ncp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
NDEFTCPPORTS * sizeof(u_short));
ncp->cfg.urgent.tos = 1;
ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = NDEFUDPPORTS;
ncp->cfg.urgent.udp.port = (u_short *)malloc(NDEFUDPPORTS * sizeof(u_short));
memcpy(ncp->cfg.urgent.udp.port, default_urgent_udp_ports,
NDEFUDPPORTS * sizeof(u_short));
mp_Init(&ncp->mp, bundle);
/* Send over the first physical link by default */
ipcp_Init(&ncp->ipcp, bundle, &bundle->links->physical->link,
&bundle->fsm);
#ifndef NOINET6
ipv6cp_Init(&ncp->ipv6cp, bundle, &bundle->links->physical->link,
&bundle->fsm);
#endif
}
void
ncp_Destroy(struct ncp *ncp)
{
ipcp_Destroy(&ncp->ipcp);
#ifndef NOINET6
ipv6cp_Destroy(&ncp->ipv6cp);
#endif
if (ncp->cfg.urgent.tcp.maxports) {
ncp->cfg.urgent.tcp.nports = ncp->cfg.urgent.tcp.maxports = 0;
free(ncp->cfg.urgent.tcp.port);
ncp->cfg.urgent.tcp.port = NULL;
}
if (ncp->cfg.urgent.udp.maxports) {
ncp->cfg.urgent.udp.nports = ncp->cfg.urgent.udp.maxports = 0;
free(ncp->cfg.urgent.udp.port);
ncp->cfg.urgent.udp.port = NULL;
}
}
int
ncp_fsmStart(struct ncp *ncp, struct bundle *bundle)
{
int res = 0;
#ifndef NOINET6
if (Enabled(bundle, OPT_IPCP)) {
#endif
fsm_Up(&ncp->ipcp.fsm);
fsm_Open(&ncp->ipcp.fsm);
res++;
#ifndef NOINET6
}
if (Enabled(bundle, OPT_IPV6CP)) {
fsm_Up(&ncp->ipv6cp.fsm);
fsm_Open(&ncp->ipv6cp.fsm);
res++;
}
#endif
return res;
}
void
ncp_IfaceAddrAdded(struct ncp *ncp, const struct iface_addr *addr)
{
switch (ncprange_family(&addr->ifa)) {
case AF_INET:
ipcp_IfaceAddrAdded(&ncp->ipcp, addr);
break;
#ifndef NOINET6
case AF_INET6:
ipv6cp_IfaceAddrAdded(&ncp->ipv6cp, addr);
break;
#endif
}
}
void
ncp_IfaceAddrDeleted(struct ncp *ncp, const struct iface_addr *addr)
{
if (ncprange_family(&addr->ifa) == AF_INET)
ipcp_IfaceAddrDeleted(&ncp->ipcp, addr);
}
void
ncp_SetLink(struct ncp *ncp, struct link *l)
{
ipcp_SetLink(&ncp->ipcp, l);
#ifndef NOINET6
ipv6cp_SetLink(&ncp->ipv6cp, l);
#endif
}
/*
* Enqueue a packet of the given address family. Nothing will make it
* down to the physical link level 'till ncp_FillPhysicalQueues() is used.
*/
void
ncp_Enqueue(struct ncp *ncp, int af, int pri, char *ptr, int count)
{
#ifndef NOINET6
struct ipv6cp *ipv6cp = &ncp->ipv6cp;
#endif
struct ipcp *ipcp = &ncp->ipcp;
struct mbuf *bp;
/*
* We allocate an extra 6 bytes, four at the front and two at the end.
* This is an optimisation so that we need to do less work in
* m_prepend() in acf_LayerPush() and proto_LayerPush() and
* appending in hdlc_LayerPush().
*/
switch (af) {
case AF_INET:
if (pri < 0 || pri >= IPCP_QUEUES(ipcp)) {
log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
break;
}
bp = m_get(count + 6, MB_IPOUT);
bp->m_offset += 4;
bp->m_len -= 6;
memcpy(MBUF_CTOP(bp), ptr, count);
m_enqueue(ipcp->Queue + pri, bp);
break;
#ifndef NOINET6
case AF_INET6:
if (pri < 0 || pri >= IPV6CP_QUEUES(ipcp)) {
log_Printf(LogERROR, "Can't store in ipv6 queue %d\n", pri);
break;
}
bp = m_get(count + 6, MB_IPOUT);
bp->m_offset += 4;
bp->m_len -= 6;
memcpy(MBUF_CTOP(bp), ptr, count);
m_enqueue(ipv6cp->Queue + pri, bp);
break;
#endif
default:
log_Printf(LogERROR, "Can't enqueue protocol family %d\n", af);
}
}
/*
* How many packets are queued to go out ?
*/
size_t
ncp_QueueLen(struct ncp *ncp)
{
size_t result;
result = ipcp_QueueLen(&ncp->ipcp);
#ifndef NOINET6
result += ipv6cp_QueueLen(&ncp->ipv6cp);
#endif
result += mp_QueueLen(&ncp->mp); /* Usually empty */
return result;
}
/*
* Ditch all queued packets. This is usually done after our choked timer
* has fired - which happens because we couldn't send any traffic over
* any links for some time.
*/
void
ncp_DeleteQueues(struct ncp *ncp)
{
#ifndef NOINET6
struct ipv6cp *ipv6cp = &ncp->ipv6cp;
#endif
struct ipcp *ipcp = &ncp->ipcp;
struct mp *mp = &ncp->mp;
struct mqueue *q;
for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
while (q->top)
m_freem(m_dequeue(q));
#ifndef NOINET6
for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
while (q->top)
m_freem(m_dequeue(q));
#endif
link_DeleteQueue(&mp->link); /* Usually empty anyway */
}
/*
* Arrange that each of our links has at least one packet. We keep the
* number of packets queued at the link level to a minimum so that the
* loss of a link in multi-link mode results in the minimum number of
* dropped packets.
*/
size_t
ncp_FillPhysicalQueues(struct ncp *ncp, struct bundle *bundle)
{
size_t total;
if (bundle->ncp.mp.active)
total = mp_FillPhysicalQueues(bundle);
else {
struct datalink *dl;
size_t add;
for (total = 0, dl = bundle->links; dl; dl = dl->next)
if (dl->state == DATALINK_OPEN) {
add = link_QueueLen(&dl->physical->link);
if (add == 0 && dl->physical->out == NULL)
add = ncp_PushPacket(ncp, &ncp->afq, &dl->physical->link);
total += add;
}
}
return total + ncp_QueueLen(&bundle->ncp);
}
/*
* Push a packet into the given link. ``af'' is used as a persistent record
* of what is to be pushed next, coming either from mp->out or ncp->afq.
*/
int
ncp_PushPacket(struct ncp *ncp, int *af, struct link *l)
{
struct bundle *bundle = l->lcp.fsm.bundle;
int res;
#ifndef NOINET6
if (*af == AF_INET) {
if ((res = ipcp_PushPacket(&bundle->ncp.ipcp, l)))
*af = AF_INET6;
else
res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l);
} else {
if ((res = ipv6cp_PushPacket(&bundle->ncp.ipv6cp, l)))
*af = AF_INET;
else
res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
}
#else
res = ipcp_PushPacket(&bundle->ncp.ipcp, l);
#endif
return res;
}
int
ncp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
{
int f;
for (f = 0; f < range->nports; f++)
if (range->port[f] == src || range->port[f] == dst)
return 1;
return 0;
}
void
ncp_AddUrgentPort(struct port_range *range, u_short port)
{
u_short *newport;
int p;
if (range->nports == range->maxports) {
range->maxports += 10;
newport = (u_short *)realloc(range->port,
range->maxports * sizeof(u_short));
if (newport == NULL) {
log_Printf(LogERROR, "ncp_AddUrgentPort: realloc: %s\n",
strerror(errno));
range->maxports -= 10;
return;
}
range->port = newport;
}
for (p = 0; p < range->nports; p++)
if (range->port[p] == port) {
log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
break;
} else if (range->port[p] > port) {
memmove(range->port + p + 1, range->port + p,
(range->nports - p) * sizeof(u_short));
range->port[p] = port;
range->nports++;
break;
}
if (p == range->nports)
range->port[range->nports++] = port;
}
void
ncp_RemoveUrgentPort(struct port_range *range, u_short port)
{
int p;
for (p = 0; p < range->nports; p++)
if (range->port[p] == port) {
if (p != range->nports - 1)
memmove(range->port + p, range->port + p + 1,
(range->nports - p - 1) * sizeof(u_short));
range->nports--;
return;
}
if (p == range->nports)
log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
}
void
ncp_ClearUrgentPorts(struct port_range *range)
{
range->nports = 0;
}
int
ncp_Show(struct cmdargs const *arg)
{
struct ncp *ncp = &arg->bundle->ncp;
int p;
#ifndef NOINET6
prompt_Printf(arg->prompt, "Next queued AF: %s\n",
ncp->afq == AF_INET6 ? "inet6" : "inet");
#endif
if (ncp->route) {
prompt_Printf(arg->prompt, "\n");
route_ShowSticky(arg->prompt, ncp->route, "Sticky routes", 1);
}
prompt_Printf(arg->prompt, "\nDefaults:\n");
prompt_Printf(arg->prompt, " sendpipe: ");
if (ncp->cfg.sendpipe > 0)
prompt_Printf(arg->prompt, "%-20ld\n", ncp->cfg.sendpipe);
else
prompt_Printf(arg->prompt, "unspecified\n");
prompt_Printf(arg->prompt, " recvpipe: ");
if (ncp->cfg.recvpipe > 0)
prompt_Printf(arg->prompt, "%ld\n", ncp->cfg.recvpipe);
else
prompt_Printf(arg->prompt, "unspecified\n");
prompt_Printf(arg->prompt, "\n Urgent ports\n");
prompt_Printf(arg->prompt, " TCP: ");
if (ncp->cfg.urgent.tcp.nports == 0)
prompt_Printf(arg->prompt, "none");
else
for (p = 0; p < ncp->cfg.urgent.tcp.nports; p++) {
if (p)
prompt_Printf(arg->prompt, ", ");
prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.tcp.port[p]);
}
prompt_Printf(arg->prompt, "\n UDP: ");
if (ncp->cfg.urgent.udp.nports == 0)
prompt_Printf(arg->prompt, "none");
else
for (p = 0; p < ncp->cfg.urgent.udp.nports; p++) {
if (p)
prompt_Printf(arg->prompt, ", ");
prompt_Printf(arg->prompt, "%u", ncp->cfg.urgent.udp.port[p]);
}
prompt_Printf(arg->prompt, "\n TOS: %s\n\n",
ncp->cfg.urgent.tos ? "yes" : "no");
return 0;
}
int
ncp_LayersOpen(struct ncp *ncp)
{
int n;
n = !!(ncp->ipcp.fsm.state == ST_OPENED);
#ifndef NOINET6
n += !!(ncp->ipv6cp.fsm.state == ST_OPENED);
#endif
return n;
}
int
ncp_LayersUnfinished(struct ncp *ncp)
{
int n = 0;
if (ncp->ipcp.fsm.state > ST_CLOSED ||
ncp->ipcp.fsm.state == ST_STARTING)
n++;
#ifndef NOINET6
if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
ncp->ipv6cp.fsm.state == ST_STARTING)
n++;
#endif
return n;
}
void
ncp_Close(struct ncp *ncp)
{
if (ncp->ipcp.fsm.state > ST_CLOSED ||
ncp->ipcp.fsm.state == ST_STARTING)
fsm_Close(&ncp->ipcp.fsm);
#ifndef NOINET6
if (ncp->ipv6cp.fsm.state > ST_CLOSED ||
ncp->ipv6cp.fsm.state == ST_STARTING)
fsm_Close(&ncp->ipv6cp.fsm);
#endif
}
void
ncp2initial(struct ncp *ncp)
{
fsm2initial(&ncp->ipcp.fsm);
#ifndef NOINET6
fsm2initial(&ncp->ipv6cp.fsm);
#endif
}

101
usr.sbin/ppp/ncp.h Normal file
View File

@ -0,0 +1,101 @@
/*-
* Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
struct port_range {
unsigned nports; /* How many ports */
unsigned maxports; /* How many allocated (malloc) ports */
u_short *port; /* The actual ports */
};
struct ncp {
struct {
u_long sendpipe; /* route sendpipe size */
u_long recvpipe; /* route recvpipe size */
struct {
struct port_range tcp, udp; /* The range of urgent ports */
unsigned tos : 1; /* Urgent IPTOS_LOWDELAY packets ? */
} urgent;
} cfg;
int afq; /* Next address family to queue */
struct sticky_route *route; /* List of dynamic routes */
struct ipcp ipcp; /* Our IPCP FSM */
#ifndef NOINET6
struct ipv6cp ipv6cp; /* Our IPV6CP FSM */
#endif
struct mp mp; /* Our MP */
};
extern void ncp_Init(struct ncp *, struct bundle *);
extern void ncp_Destroy(struct ncp *);
extern int ncp_fsmStart(struct ncp *, struct bundle *);
extern void ncp_IfaceAddrAdded(struct ncp *, const struct iface_addr *);
extern void ncp_IfaceAddrDeleted(struct ncp *, const struct iface_addr *);
extern void ncp_SetLink(struct ncp *, struct link *);
extern void ncp_Enqueue(struct ncp *, int, int, char *, int);
extern void ncp_DeleteQueues(struct ncp *);
extern size_t ncp_QueueLen(struct ncp *);
extern size_t ncp_FillPhysicalQueues(struct ncp *, struct bundle *);
extern int ncp_PushPacket(struct ncp *, int *, struct link *);
extern int ncp_IsUrgentPort(struct port_range *, u_short, u_short);
extern void ncp_AddUrgentPort(struct port_range *, u_short);
extern void ncp_RemoveUrgentPort(struct port_range *, u_short);
extern void ncp_ClearUrgentPorts(struct port_range *);
extern int ncp_Show(struct cmdargs const *);
extern int ncp_LayersOpen(struct ncp *);
extern int ncp_LayersUnfinished(struct ncp *);
extern void ncp_Close(struct ncp *);
extern void ncp2initial(struct ncp *);
#define ncp_IsUrgentTcpPort(ncp, p1, p2) \
ncp_IsUrgentPort(&(ncp)->cfg.urgent.tcp, p1, p2)
#define ncp_IsUrgentUdpPort(ncp, p1, p2) \
ncp_IsUrgentPort(&(ncp)->cfg.urgent.udp, p1, p2)
#define ncp_AddUrgentTcpPort(ncp, p) \
ncp_AddUrgentPort(&(ncp)->cfg.urgent.tcp, p)
#define ncp_AddUrgentUdpPort(ncp, p) \
ncp_AddUrgentPort(&(ncp)->cfg.urgent.udp, p)
#define ncp_RemoveUrgentTcpPort(ncp, p) \
ncp_RemoveUrgentPort(&(ncp)->cfg.urgent.tcp, p)
#define ncp_RemoveUrgentUdpPort(ncp, p) \
ncp_RemoveUrgentPort(&(ncp)->cfg.urgent.udp, p)
#define ncp_ClearUrgentTcpPorts(ncp) \
ncp_ClearUrgentPorts(&(ncp)->cfg.urgent.tcp)
#define ncp_ClearUrgentUdpPorts(ncp) \
ncp_ClearUrgentPorts(&(ncp)->cfg.urgent.udp)
#define ncp_ClearUrgentTOS(ncp) (ncp)->cfg.urgent.tos = 0;
#define ncp_SetUrgentTOS(ncp) (ncp)->cfg.urgent.tos = 1;
#ifndef NOINET6
#define isncp(proto) ((proto) == PROTO_IPCP || (proto) == PROTO_IPV6CP)
#else
#define isncp(proto) ((proto) == PROTO_IPCP)
#endif

967
usr.sbin/ppp/ncpaddr.c Normal file
View File

@ -0,0 +1,967 @@
/*-
* Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <limits.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include "log.h"
#include "ncpaddr.h"
#include "timer.h"
#include "fsm.h"
#include "defs.h"
#include "slcompress.h"
#include "iplist.h"
#include "throughput.h"
#include "mbuf.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
#include "route.h"
#include "layer.h"
#include "lqr.h"
#include "hdlc.h"
#include "lcp.h"
#include "ccp.h"
#include "link.h"
#include "mp.h"
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#define ncprange_ip4addr u.ip4.ipaddr
#define ncprange_ip4mask u.ip4.mask
#define ncprange_ip4width u.ip4.width
#define ncpaddr_ip4addr u.ip4addr
#ifndef NOINET6
#define ncprange_ip6addr u.ip6.ipaddr
#define ncprange_ip6width u.ip6.width
#define ncpaddr_ip6addr u.ip6addr
#endif
#define NCP_ASCIIBUFFERSIZE 52
static struct in_addr
bits2mask4(int bits)
{
struct in_addr result;
u_int32_t bit = 0x80000000;
result.s_addr = 0;
while (bits) {
result.s_addr |= bit;
bit >>= 1;
bits--;
}
result.s_addr = htonl(result.s_addr);
return result;
}
static int
mask42bits(struct in_addr mask)
{
u_int32_t msk = ntohl(mask.s_addr);
u_int32_t tst;
int ret;
for (ret = 32, tst = 1; tst; ret--, tst <<= 1)
if (msk & tst)
break;
for (tst <<= 1; tst; tst <<= 1)
if (!(msk & tst))
break;
return tst ? -1 : ret;
}
#ifndef NOINET6
static struct in6_addr
bits2mask6(int bits)
{
struct in6_addr result;
u_int32_t bit = 0x80;
u_char *c = result.s6_addr;
memset(&result, '\0', sizeof result);
while (bits) {
if (bit == 0) {
bit = 0x80;
c++;
}
*c |= bit;
bit >>= 1;
bits--;
}
return result;
}
static int
mask62bits(const struct in6_addr *mask)
{
const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
const u_char *c, *p, *end;
int masklen;
p = (const u_char *)mask;
for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
masklen += 8;
if (p < end) {
for (c = masks; c < masks + sizeof masks; c++)
if (*c == *p) {
masklen += c - masks;
break;
}
}
return masklen;
}
static void
adjust_linklocal(struct sockaddr_in6 *sin6)
{
/* XXX: ?????!?!?!!!!! This is horrible ! */
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
sin6->sin6_scope_id =
ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]);
*(u_short *)&sin6->sin6_addr.s6_addr[2] = 0;
}
}
#endif
void
ncpaddr_init(struct ncpaddr *addr)
{
addr->ncpaddr_family = AF_UNSPEC;
}
int
ncpaddr_isdefault(const struct ncpaddr *addr)
{
switch (addr->ncpaddr_family) {
case AF_INET:
if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY)
return 1;
break;
#ifndef NOINET6
case AF_INET6:
if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr))
return 1;
break;
#endif
}
return 0;
}
int
ncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp)
{
if (addr->ncpaddr_family != cmp->ncpaddr_family)
return 0;
switch (addr->ncpaddr_family) {
case AF_INET:
return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr;
#ifndef NOINET6
case AF_INET6:
return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr,
sizeof addr->ncpaddr_ip6addr);
#endif
case AF_UNSPEC:
return 1;
}
return 0;
}
void
ncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from)
{
switch (from->ncpaddr_family) {
case AF_INET:
addr->ncpaddr_family = AF_INET;
addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr;
break;
#ifndef NOINET6
case AF_INET6:
addr->ncpaddr_family = AF_INET6;
addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr;
break;
#endif
default:
addr->ncpaddr_family = AF_UNSPEC;
}
}
void
ncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip)
{
addr->ncpaddr_family = AF_INET;
addr->ncpaddr_ip4addr.s_addr = ip;
}
int
ncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip)
{
if (addr->ncpaddr_family != AF_INET)
return 0;
*ip = addr->ncpaddr_ip4addr.s_addr;
return 1;
}
void
ncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip)
{
addr->ncpaddr_family = AF_INET;
addr->ncpaddr_ip4addr = ip;
}
int
ncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip)
{
if (addr->ncpaddr_family != AF_INET)
return 0;
*ip = addr->ncpaddr_ip4addr;
return 1;
}
#ifndef NOINET6
void
ncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6)
{
addr->ncpaddr_family = AF_INET6;
addr->ncpaddr_ip6addr = *ip6;
}
int
ncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6)
{
if (addr->ncpaddr_family != AF_INET6)
return 0;
*ip6 = addr->ncpaddr_ip6addr;
return 1;
}
#endif
void
ncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host)
{
struct sockaddr_in *host4 = (struct sockaddr_in *)host;
#ifndef NOINET6
struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
#endif
memset(host, '\0', sizeof(*host));
switch (addr->ncpaddr_family) {
case AF_INET:
host4->sin_family = AF_INET;
host4->sin_len = sizeof(*host4);
host4->sin_addr = addr->ncpaddr_ip4addr;
break;
#ifndef NOINET6
case AF_INET6:
host6->sin6_family = AF_INET6;
host6->sin6_len = sizeof(*host6);
host6->sin6_addr = addr->ncpaddr_ip6addr;
adjust_linklocal(host6);
break;
#endif
default:
host->ss_family = AF_UNSPEC;
break;
}
}
void
ncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host)
{
const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
#ifndef NOINET6
const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
#endif
switch (host->sa_family) {
case AF_INET:
addr->ncpaddr_family = AF_INET;
addr->ncpaddr_ip4addr = host4->sin_addr;
break;
#ifndef NOINET6
case AF_INET6:
if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) {
addr->ncpaddr_family = AF_INET;
addr->ncpaddr_ip4addr.s_addr =
*(const u_int32_t *)(host6->sin6_addr.s6_addr + 12);
} else {
addr->ncpaddr_family = AF_INET6;
addr->ncpaddr_ip6addr = host6->sin6_addr;
}
break;
#endif
default:
addr->ncpaddr_family = AF_UNSPEC;
}
}
static char *
ncpaddr_ntowa(const struct ncpaddr *addr)
{
static char res[NCP_ASCIIBUFFERSIZE];
#ifndef NOINET6
struct sockaddr_in6 sin6;
#endif
switch (addr->ncpaddr_family) {
case AF_INET:
snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr));
return res;
#ifndef NOINET6
case AF_INET6:
memset(&sin6, '\0', sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = addr->ncpaddr_ip6addr;
adjust_linklocal(&sin6);
if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0)
break;
return res;
#endif
}
snprintf(res, sizeof res, "<AF_UNSPEC>");
return res;
}
const char *
ncpaddr_ntoa(const struct ncpaddr *addr)
{
return ncpaddr_ntowa(addr);
}
int
ncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
{
struct ncprange range;
if (!ncprange_aton(&range, ncp, data))
return 0;
if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) {
log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
return 0;
}
#ifndef NOINET6
if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) {
log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
return 0;
}
#endif
switch (range.ncprange_family) {
case AF_INET:
addr->ncpaddr_family = range.ncprange_family;
addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
return 1;
#ifndef NOINET6
case AF_INET6:
addr->ncpaddr_family = range.ncprange_family;
addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
return 1;
#endif
}
return 0;
}
void
ncprange_init(struct ncprange *range)
{
range->ncprange_family = AF_UNSPEC;
}
int
ncprange_isset(const struct ncprange *range)
{
return range->ncprange_family != AF_UNSPEC;
}
int
ncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
{
if (range->ncprange_family != cmp->ncprange_family)
return 0;
switch (range->ncprange_family) {
case AF_INET:
if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
return 0;
return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
#ifndef NOINET6
case AF_INET6:
if (range->ncprange_ip6width != cmp->ncprange_ip6width)
return 0;
return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
sizeof range->ncprange_ip6addr);
#endif
case AF_UNSPEC:
return 1;
}
return 0;
}
int
ncprange_isdefault(const struct ncprange *range)
{
switch (range->ncprange_family) {
case AF_INET:
if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
return 1;
break;
#ifndef NOINET6
case AF_INET6:
if (range->ncprange_ip6width == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
return 1;
break;
#endif
}
return 0;
}
void
ncprange_setdefault(struct ncprange *range, int af)
{
memset(range, '\0', sizeof *range);
range->ncprange_family = af;
}
int
ncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
{
#ifndef NOINET6
const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
const u_char *addrp, *rangep;
int bits;
#endif
if (range->ncprange_family != addr->ncpaddr_family)
return 0;
switch (range->ncprange_family) {
case AF_INET:
return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
range->ncprange_ip4mask.s_addr);
#ifndef NOINET6
case AF_INET6:
rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
return 0;
return 1;
#endif
}
return 0;
}
int
ncprange_containsip4(const struct ncprange *range, struct in_addr addr)
{
switch (range->ncprange_family) {
case AF_INET:
return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
range->ncprange_ip4mask.s_addr);
}
return 0;
}
void
ncprange_copy(struct ncprange *range, const struct ncprange *from)
{
switch (from->ncprange_family) {
case AF_INET:
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = from->ncprange_ip4addr;
range->ncprange_ip4mask = from->ncprange_ip4mask;
range->ncprange_ip4width = from->ncprange_ip4width;
break;
#ifndef NOINET6
case AF_INET6:
range->ncprange_family = AF_INET6;
range->ncprange_ip6addr = from->ncprange_ip6addr;
range->ncprange_ip6width = from->ncprange_ip6width;
break;
#endif
default:
range->ncprange_family = AF_UNSPEC;
}
}
void
ncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
{
ncprange_sethost(range, addr);
ncprange_setwidth(range, width);
}
void
ncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
{
switch (from->ncpaddr_family) {
case AF_INET:
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = from->ncpaddr_ip4addr;
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
break;
#ifndef NOINET6
case AF_INET6:
range->ncprange_family = AF_INET6;
range->ncprange_ip6addr = from->ncpaddr_ip6addr;
range->ncprange_ip6width = 128;
break;
#endif
default:
range->ncprange_family = AF_UNSPEC;
}
}
int
ncprange_setwidth(struct ncprange *range, int width)
{
switch (range->ncprange_family) {
case AF_INET:
if (width < 0 || width > 32)
break;
range->ncprange_ip4width = width;
range->ncprange_ip4mask = bits2mask4(width);
break;
#ifndef NOINET6
case AF_INET6:
if (width < 0 || width > 128)
break;
range->ncprange_ip6width = width;
break;
#endif
case AF_UNSPEC:
return 1;
}
return 0;
}
void
ncprange_setip4host(struct ncprange *range, struct in_addr from)
{
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = from;
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
}
void
ncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
{
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = from;
range->ncprange_ip4mask = msk;
range->ncprange_ip4width = mask42bits(msk);
}
int
ncprange_setip4mask(struct ncprange *range, struct in_addr mask)
{
if (range->ncprange_family != AF_INET)
return 0;
range->ncprange_ip4mask = mask;
range->ncprange_ip4width = mask42bits(mask);
return 1;
}
void
ncprange_setsa(struct ncprange *range, const struct sockaddr *host,
const struct sockaddr *mask)
{
const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
#ifndef NOINET6
const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
#endif
switch (host->sa_family) {
case AF_INET:
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = host4->sin_addr;
if (mask4) {
range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
range->ncprange_ip4width = mask42bits(mask4->sin_addr);
} else {
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
}
break;
#ifndef NOINET6
case AF_INET6:
range->ncprange_family = AF_INET6;
range->ncprange_ip6addr = host6->sin6_addr;
range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
break;
#endif
default:
range->ncprange_family = AF_UNSPEC;
}
}
void
ncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
struct sockaddr_storage *mask)
{
struct sockaddr_in *host4 = (struct sockaddr_in *)host;
struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
#ifndef NOINET6
struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
#endif
memset(host, '\0', sizeof(*host));
if (mask)
memset(mask, '\0', sizeof(*mask));
switch (range->ncprange_family) {
case AF_INET:
host4->sin_family = AF_INET;
host4->sin_len = sizeof(*host4);
host4->sin_addr = range->ncprange_ip4addr;
if (mask4) {
mask4->sin_family = AF_INET;
mask4->sin_len = sizeof(*host4);
mask4->sin_addr = bits2mask4(range->ncprange_ip4width);
}
break;
#ifndef NOINET6
case AF_INET6:
host6->sin6_family = AF_INET6;
host6->sin6_len = sizeof(*host6);
host6->sin6_addr = range->ncprange_ip6addr;
adjust_linklocal(host6);
if (mask6) {
mask6->sin6_family = AF_INET6;
mask6->sin6_len = sizeof(*host6);
mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
}
break;
#endif
default:
host->ss_family = AF_UNSPEC;
if (mask)
mask->ss_family = AF_UNSPEC;
break;
}
}
int
ncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
{
switch (range->ncprange_family) {
case AF_INET:
addr->ncpaddr_family = AF_INET;
addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
return 1;
#ifndef NOINET6
case AF_INET6:
addr->ncpaddr_family = AF_INET6;
addr->ncpaddr_ip6addr = range->ncprange_ip6addr;
return 1;
#endif
}
return 0;
}
int
ncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
{
if (range->ncprange_family != AF_INET)
return 0;
*addr = range->ncprange_ip4addr;
return 1;
}
int
ncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
{
switch (range->ncprange_family) {
case AF_INET:
*mask = range->ncprange_ip4mask;
return 1;
}
return 0;
}
int
ncprange_getwidth(const struct ncprange *range, int *width)
{
switch (range->ncprange_family) {
case AF_INET:
*width = range->ncprange_ip4width;
return 1;
#ifndef NOINET6
case AF_INET6:
*width = range->ncprange_ip6width;
return 1;
#endif
}
return 0;
}
const char *
ncprange_ntoa(const struct ncprange *range)
{
char *res;
struct ncpaddr addr;
int len;
if (!ncprange_getaddr(range, &addr))
return "<AF_UNSPEC>";
res = ncpaddr_ntowa(&addr);
len = strlen(res);
if (len >= NCP_ASCIIBUFFERSIZE - 1)
return res;
switch (range->ncprange_family) {
case AF_INET:
if (range->ncprange_ip4width == -1) {
/* A non-contiguous mask */
for (; len >= 3; res[len -= 2] = '\0')
if (strcmp(res + len - 2, ".0"))
break;
snprintf(res + len, sizeof res - len, "&0x%08lx",
ntohl(range->ncprange_ip4mask.s_addr));
} else if (range->ncprange_ip4width < 32)
snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
return res;
#ifndef NOINET6
case AF_INET6:
if (range->ncprange_ip6width != 128)
snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
return res;
#endif
}
return "<AF_UNSPEC>";
}
#ifndef NOINET6
int
ncprange_scopeid(const struct ncprange *range)
{
const struct in6_addr *sin6;
int scopeid = -1;
if (range->ncprange_family == AF_INET6) {
sin6 = &range->ncprange_ip6addr;
if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
scopeid = -1;
}
return scopeid;
}
#endif
int
ncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
{
int bits, len;
char *wp;
const char *cp;
char *s;
len = strcspn(data, "/");
if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = ncp->ipcp.peer_ip;
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
return 1;
#ifndef NOINET6
} else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
ncprange_sethost(range, &ncp->ipv6cp.hisaddr);
return 1;
#endif
} else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = ncp->ipcp.my_ip;
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
return 1;
#ifndef NOINET6
} else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
ncprange_sethost(range, &ncp->ipv6cp.myaddr);
return 1;
#endif
} else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
return 1;
} else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
return 1;
}
s = (char *)alloca(len + 1);
strncpy(s, data, len);
s[len] = '\0';
bits = -1;
if (data[len] != '\0') {
bits = strtol(data + len + 1, &wp, 0);
if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
return 0;
}
}
if ((cp = strchr(data, ':')) == NULL) {
range->ncprange_family = AF_INET;
range->ncprange_ip4addr = GetIpAddr(s);
if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
return 0;
}
if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
range->ncprange_ip4mask.s_addr = INADDR_ANY;
range->ncprange_ip4width = 0;
} else if (data[len] == '\0') {
range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
range->ncprange_ip4width = 32;
} else {
if (bits > 32) {
log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
return 0;
}
range->ncprange_ip4mask = bits2mask4(bits);
range->ncprange_ip4width = bits;
}
return 1;
#ifndef NOINET6
} else if (strchr(cp + 1, ':') != NULL) {
range->ncprange_family = AF_INET6;
if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
return 0;
}
if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
range->ncprange_ip6width = 0;
else
range->ncprange_ip6width = (bits == -1) ? 128 : bits;
return 1;
#endif
}
return 0;
}

107
usr.sbin/ppp/ncpaddr.h Normal file
View File

@ -0,0 +1,107 @@
/*-
* Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* These structures should be treated as opaque.
*/
struct ncprange {
sa_family_t ncprange_family;
union {
struct {
struct in_addr ipaddr;
struct in_addr mask;
int width;
} ip4;
#ifndef NOINET6
struct {
struct in6_addr ipaddr;
int width;
} ip6;
#endif
} u;
};
struct ncpaddr {
sa_family_t ncpaddr_family;
union {
struct in_addr ip4addr;
#ifndef NOINET6
struct in6_addr ip6addr;
#endif
} u;
};
struct ncp;
extern void ncpaddr_init(struct ncpaddr *);
extern int ncpaddr_isdefault(const struct ncpaddr *);
extern int ncpaddr_equal(const struct ncpaddr *, const struct ncpaddr *);
extern void ncpaddr_copy(struct ncpaddr *, const struct ncpaddr *);
extern void ncpaddr_setip4addr(struct ncpaddr *, u_int32_t);
extern int ncpaddr_getip4addr(const struct ncpaddr *, u_int32_t *);
extern void ncpaddr_setip4(struct ncpaddr *, struct in_addr);
extern int ncpaddr_getip4(const struct ncpaddr *, struct in_addr *);
#ifndef NOINET6
extern void ncpaddr_setip6(struct ncpaddr *, const struct in6_addr *);
extern int ncpaddr_getip6(const struct ncpaddr *, struct in6_addr *);
#endif
extern void ncpaddr_getsa(const struct ncpaddr *, struct sockaddr_storage *);
extern void ncpaddr_setsa(struct ncpaddr *, const struct sockaddr *);
extern const char *ncpaddr_ntoa(const struct ncpaddr *);
extern int ncpaddr_aton(struct ncpaddr *, struct ncp *, const char *);
extern void ncprange_init(struct ncprange *);
extern int ncprange_isset(const struct ncprange *);
extern int ncprange_equal(const struct ncprange *, const struct ncprange *);
extern int ncprange_isdefault(const struct ncprange *);
extern void ncprange_setdefault(struct ncprange *, int);
extern int ncprange_contains(const struct ncprange *, const struct ncpaddr *);
extern int ncprange_containsip4(const struct ncprange *, struct in_addr);
extern void ncprange_copy(struct ncprange *, const struct ncprange *);
extern void ncprange_set(struct ncprange *, const struct ncpaddr *, int);
extern void ncprange_sethost(struct ncprange *, const struct ncpaddr *);
extern int ncprange_setwidth(struct ncprange *, int);
extern void ncprange_setip4(struct ncprange *, struct in_addr, struct in_addr);
extern void ncprange_setip4host(struct ncprange *, struct in_addr);
extern int ncprange_setip4mask(struct ncprange *, struct in_addr);
extern void ncprange_setsa(struct ncprange *, const struct sockaddr *,
const struct sockaddr *);
extern void ncprange_getsa(const struct ncprange *, struct sockaddr_storage *,
struct sockaddr_storage *);
extern int ncprange_getaddr(const struct ncprange *, struct ncpaddr *);
extern int ncprange_getip4addr(const struct ncprange *, struct in_addr *);
extern int ncprange_getip4mask(const struct ncprange *, struct in_addr *);
extern int ncprange_getwidth(const struct ncprange *, int *);
extern const char *ncprange_ntoa(const struct ncprange *);
#ifndef NOINET6
extern int ncprange_scopeid(const struct ncprange *);
#endif
extern int ncprange_aton(struct ncprange *, struct ncp *, const char *);
#define ncpaddr_family(a) ((a)->ncpaddr_family)
#define ncprange_family(r) ((r)->ncprange_family)

View File

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
@ -58,12 +59,16 @@
#include "physical.h"
#include "iplist.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "mp.h"
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "chat.h"
#include "chap.h"

View File

@ -24,6 +24,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
@ -69,6 +70,8 @@
#include "async.h"
#include "iplist.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -79,6 +82,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "prompt.h"
#include "chat.h"

View File

@ -396,6 +396,9 @@ For now,
can only get encryption keys from CHAP 81 authentication.
.Nm
must be compiled with DES for MPPE to operate.
.It Supports IPV6CP (rfc 2023).
An IPv6 connection can be made in addition to or instead of the normal
IPv4 connection.
.El
.Sh PERMISSIONS
.Nm
@ -719,6 +722,8 @@ PPP ON awfulhak> show lcp
* LCP (line control) related information is shown here *
PPP ON awfulhak> show ipcp
* IPCP (IP) related information is shown here *
PPP ON awfulhak> show ipv6cp
* IPV6CP (IPv6) related information is shown here *
PPP ON awfulhak> show link
* Link (high level) related information is shown here *
PPP ON awfulhak> show bundle
@ -903,16 +908,15 @@ it was necessary to re-add routes such as the default route in the
.Pa ppp.linkup
file.
.Nm
now supports
supports
.Sq sticky routes ,
where all routes that contain the
.Dv HISADDR
.Dv HISADDR ,
.Dv MYADDR ,
.Dv HISADDR6
or
.Dv MYADDR
literals will automatically be updated when the values of
.Dv HISADDR
and/or
.Dv MYADDR
.Dv MYADDR6
literals will automatically be updated when the values of these variables
change.
.Sh BACKGROUND DIALING
If you want to establish a connection using
@ -1502,7 +1506,7 @@ ui-gate:
set device ui-gate:ppp-in/tcp
set dial
set timeout 30
set log Phase Chat Connect hdlc LCP IPCP CCP tun
set log Phase Chat Connect hdlc LCP IPCP IPV6CP CCP tun
set ifaddr 10.0.4.2 10.0.4.1
.Ed
.Pp
@ -1738,9 +1742,11 @@ Either
or
.Ar dst_addr
may be given the values
.Dv MYADDR
.Dv MYADDR ,
.Dv HISADDR ,
.Dv MYADDR6
or
.Dv HISADDR
.Dv HISADDR6
(refer to the description of the
.Dq bg
command for a description of these values).
@ -1751,14 +1757,8 @@ This is similar to the behaviour of the
command below.
.It
.Ar Proto
must be one of
.Sq icmp ,
.Sq igmp ,
.Sq ipip ,
.Sq ospf ,
.Sq udp
or
.Sq tcp .
may be any protocol from
.Xr protocols 5 .
.It
.Ar Cmp
is one of
@ -1889,19 +1889,20 @@ to successfully negotiate DEFLATE with
.Nm pppd
version 2.3.*.
.Sh CONTROLLING IP ADDRESS
For IPv4,
.Nm
uses IPCP to negotiate IP addresses.
Each side of the connection
specifies the IP address that it's willing to use, and if the requested
IP address is acceptable then
.Nm
returns ACK to the requester.
returns an ACK to the requester.
Otherwise,
.Nm
returns NAK to suggest that the peer use a different IP address.
When
both sides of the connection agree to accept the received request (and
send ACK), IPCP is set to the open state and a network level connection
send an ACK), IPCP is set to the open state and a network level connection
is established.
To control this IPCP behaviour, this implementation has the
.Dq set ifaddr
@ -1999,8 +2000,11 @@ When using zero, no routing table entries will be made until a connection
is established.
.It
192.244.177.2/0 means that I'll accept/permit any IP address but I'll
try to insist that 192.244.177.2 be used first.
suggest that 192.244.177.2 be used first.
.El
.Pp
When negotiating IPv6 addresses, no control is given to the user.
IPV6CP negotiation is fully automatic.
.Sh CONNECTING WITH YOUR INTERNET SERVICE PROVIDER
The following steps should be taken when connecting to your ISP:
.Bl -enum
@ -2210,7 +2214,10 @@ add default HISADDR
.Ed
.Pp
to
.Pa /etc/ppp/ppp.conf .
.Pa /etc/ppp/ppp.conf
(or to
.Pa /etc/ppp/ppp.linkup
for setups that don't use -auto mode).
.Pp
This tells
.Nm
@ -2221,15 +2228,6 @@ This route is
meaning that should the value of
.Dv HISADDR
change, the route will be updated accordingly.
.Pp
Previous versions of
.Nm
required a similar entry in the
.Pa /etc/ppp/ppp.linkup
file.
Since the advent of
.Sq sticky routes ,
this is no longer required.
.It
If your provider requests that you use PAP/CHAP authentication methods, add
the next lines to your
@ -2948,6 +2946,43 @@ If
is disabled,
.Nm
will ignore the identifier field.
.It iface-alias
Default: Enabled if
.Fl nat
is specified.
This option simply tells
.Nm
to add new interface addresses to the interface rather than replacing them.
The option can only be enabled if network address translation is enabled
.Pq Dq nat enable yes .
.Pp
With this option enabled,
.Nm
will pass traffic for old interface addresses through the NAT
ifdef({LOCALNAT},{engine,},{engine
(see
.Xr libalias 3 ) ,})
resulting in the ability (in
.Fl auto
mode) to properly connect the process that caused the PPP link to
come up in the first place.
.Pp
Disabling NAT with
.Dq nat enable no
will also disable
.Sq iface-alias .
.It ipcp
Default: Enabled.
This option allows
.Nm
to attempt to negotiate IP control protocol capabilities and if
successful to exchange IP datagrams with the peer.
.It ipv6cp
Default: Enabled.
This option allows
.Nm
to attempt to negotiate IPv6 control protocol capabilities and if
successful to exchange IPv6 datagrams with the peer.
.It keep-session
Default: Disabled.
When
@ -3058,17 +3093,15 @@ Default: Enabled.
When the
.Dq add
command is used with the
.Dv HISADDR
.Dv HISADDR ,
.Dv MYADDR ,
.Dv HISADDR6
or
.Dv MYADDR
.Dv MYADDR6
values, entries are stored in the
.Sq stick route
.Sq sticky route
list.
Each time
.Dv HISADDR
or
.Dv MYADDR
change, this list is re-applied to the routing table.
Each time these variables change, this list is re-applied to the routing table.
.Pp
Disabling this option will prevent the re-application of sticky routes,
although the
@ -3111,31 +3144,6 @@ Disabling this option will tell
not to make any utmp or wtmp entries.
This is usually only necessary if
you require the user to both login and authenticate themselves.
.It iface-alias
Default: Enabled if
.Fl nat
is specified.
This option simply tells
.Nm
to add new interface addresses to the interface rather than replacing them.
The option can only be enabled if network address translation is enabled
.Pq Dq nat enable yes .
.Pp
With this option enabled,
.Nm
will pass traffic for old interface addresses through the NAT
ifdef({LOCALNAT},{engine,},{engine
(see
.Xr libalias 3 ) ,})
resulting in the ability (in
.Fl auto
mode) to properly connect the process that caused the PPP link to
come up in the first place.
.Pp
Disabling NAT with
.Dq nat enable no
will also disable
.Sq iface-alias .
.El
.Pp
.It add Ns Xo
@ -3167,17 +3175,25 @@ Refer to the
command for further details.
.Pp
It is possible to use the symbolic names
.Sq MYADDR
.Sq MYADDR ,
.Sq HISADDR ,
.Sq MYADDR6
or
.Sq HISADDR
.Sq HISADDR6
as the destination, and
.Sq HISADDR
or
.Sq HISADDR6
as the
.Ar gateway .
.Sq MYADDR
is replaced with the interface address and
is replaced with the interface IP address,
.Sq HISADDR
is replaced with the interface destination (peer) address.
is replaced with the interface IP destination (peer) address,
.Sq MYADDR6
is replaced with the interface IPv6 address, and
.Sq HISADDR6
is replaced with the interface IPv6 destination address,
.Pp
If the
.Ar add!\&
@ -3193,19 +3209,16 @@ for further details).
Routes that contain the
.Dq HISADDR ,
.Dq MYADDR ,
.Dq HISADDR6 ,
.Dq MYADDR6 ,
.Dq DNS0 ,
or
.Dq DNS1
constants are considered
.Sq sticky .
They are stored in a list (use
.Dq show ipcp
to see the list), and each time the value of
.Dv HISADDR ,
.Dv MYADDR ,
.Dv DNS0 ,
or
.Dv DNS1
.Dq show ncp
to see the list), and each time the value of one of these variables
changes, the appropriate routing table entries are updated.
This facility may be disabled using
.Dq disable sroutes .
@ -3500,6 +3513,8 @@ See the
command below.
.It Li HISADDR
This is replaced with the peers IP number.
.It Li HISADDR6
This is replaced with the peers IPv6 number.
.It Li INTERFACE
This is replaced with the name of the interface that's in use.
.It Li LABEL
@ -3515,6 +3530,8 @@ commands and in the
file.
.It Li MYADDR
This is replaced with the IP number assigned to the local interface.
.It Li MYADDR6
This is replaced with the IPv6 number assigned to the local interface.
.It Li PEER_ENDDISC
This is replaced with the value of the peers endpoint discriminator.
.It Li PROCESSID
@ -3538,11 +3555,12 @@ If you wish to pause
while the command executes, use the
.Dq shell
command instead.
.It clear physical|ipcp Op current|overall|peak...
.It clear physical|ipcp|ipv6 Op current|overall|peak...
Clear the specified throughput values at either the
.Dq physical
or
.Dq physical ,
.Dq ipcp
or
.Dq ipv6cp
level.
If
.Dq physical
@ -3712,12 +3730,12 @@ defaults to
This address (the broadcast address) is the only duplicate peer address that
.Nm
allows.
.It iface clear
.It iface clear Op INET | INET6
If this command is used while
.Nm
is in the OPENED state or while in
.Fl auto
mode, all addresses except for the IPCP negotiated address are deleted
mode, all addresses except for the NCP negotiated address are deleted
from the interface.
If
.Nm
@ -3725,6 +3743,9 @@ is not in the OPENED state and is not in
.Fl auto
mode, all interface addresses are deleted.
.Pp
If the INET or INET6 arguments are used, only addresses for that address
family are cleared.
.Pp
.It iface delete Ns Xo
.Op !\& Ns
.No |rm Ns Op !\&
@ -4698,7 +4719,7 @@ as they travel across the link.
.Oo Op host
.Ar src_addr Ns Op / Ns Ar width
.Op Ar dst_addr Ns Op / Ns Ar width
.Oc [ tcp|udp|ospf|ipip|igmp|icmp Op src lt|eq|gt Ar port
.Oc [ Ns Ar proto Op src lt|eq|gt Ar port
.Op dst lt|eq|gt Ar port
.Op estab
.Op syn
@ -5577,6 +5598,8 @@ Show a list of available logical links.
Show the current log values.
.It show mem
Show current memory statistics.
.It show ncp
Show the current NCP statistics.
.It show physical
Show low level link information.
.It show mp

View File

@ -30,6 +30,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
@ -57,6 +58,8 @@
#include "lqr.h"
#include "hdlc.h"
#include "lcp.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "async.h"
@ -67,6 +70,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "chat.h"
#include "chap.h"

View File

@ -35,12 +35,18 @@
#define PROTO_VJUNCOMP 0x002f /* VJ Uncompressed */
#define PROTO_VJCOMP 0x002d /* VJ Compressed */
#define PROTO_MP 0x003d /* Multilink fragment */
#ifndef NOINET6
#define PROTO_IPV6 0x0057 /* IPv6 */
#endif
#define PROTO_ICOMPD 0x00fb /* Individual link compressed */
#define PROTO_COMPD 0x00fd /* Compressed datagram */
#define PROTO_COMPRESSIBLE(p) (((p) & 0xffe1) == 0x21)
#define PROTO_IPCP 0x8021
#ifndef NOINET6
#define PROTO_IPV6CP 0x8057
#endif
#define PROTO_ICCP 0x80fb
#define PROTO_CCP 0x80fd

View File

@ -65,7 +65,10 @@
#include "lqr.h"
#include "hdlc.h"
#include "mbuf.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "ipv6cp.h"
#include "route.h"
#include "command.h"
#include "filter.h"
@ -81,6 +84,7 @@
#include "cbcp.h"
#include "chap.h"
#include "datalink.h"
#include "ncp.h"
#include "bundle.h"
/*
@ -91,12 +95,14 @@ radius_Process(struct radius *r, int got)
{
char *argv[MAXARGS], *nuke;
struct bundle *bundle;
int argc, addrs;
int argc, addrs, width;
size_t len;
struct in_range dest;
struct in_addr gw;
struct ncprange dest;
struct ncpaddr gw;
const void *data;
const char *stype;
u_int32_t ipaddr;
struct in_addr ip;
r->cx.fd = -1; /* Stop select()ing */
stype = r->cx.auth ? "auth" : "acct";
@ -199,8 +205,8 @@ radius_Process(struct radius *r, int got)
log_Printf(LogPHASE, " Route: %s\n", nuke);
bundle = r->cx.auth->physical->dl->bundle;
dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY;
dest.width = 0;
ip.s_addr = INADDR_ANY;
ncprange_setip4host(&dest, ip);
argc = command_Interpret(nuke, strlen(nuke), argv);
if (argc < 0)
log_Printf(LogWARN, "radius: %s: Syntax error\n",
@ -209,15 +215,17 @@ radius_Process(struct radius *r, int got)
log_Printf(LogWARN, "radius: %s: Invalid route\n",
argc == 1 ? argv[0] : "\"\"");
else if ((strcasecmp(argv[0], "default") != 0 &&
!ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr,
&dest.mask, &dest.width)) ||
!ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL))
!ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
!ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
argv[0], argv[1]);
else {
if (dest.width == 32 && strchr(argv[0], '/') == NULL)
ncprange_getwidth(&dest, &width);
if (width == 32 && strchr(argv[0], '/') == NULL) {
/* No mask specified - use the natural mask */
dest.mask = addr2mask(dest.ipaddr);
ncprange_getip4addr(&dest, &ip);
ncprange_setip4mask(&dest, addr2mask(ip));
}
addrs = 0;
if (!strncasecmp(argv[0], "HISADDR", 7))
@ -225,13 +233,13 @@ radius_Process(struct radius *r, int got)
else if (!strncasecmp(argv[0], "MYADDR", 6))
addrs = ROUTE_DSTMYADDR;
if (gw.s_addr == INADDR_ANY) {
if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
addrs |= ROUTE_GWHISADDR;
gw = bundle->ncp.ipcp.peer_ip;
ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
} else if (strcasecmp(argv[1], "HISADDR") == 0)
addrs |= ROUTE_GWHISADDR;
route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw);
route_Add(&r->routes, addrs, &dest, &gw);
}
free(nuke);
break;

View File

@ -64,6 +64,8 @@
#include "ccp.h"
#include "link.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -71,6 +73,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "route.h"
#include "prompt.h"
@ -82,9 +86,8 @@ static void
p_sockaddr(struct prompt *prompt, struct sockaddr *phost,
struct sockaddr *pmask, int width)
{
struct ncprange range;
char buf[29];
struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost;
struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask;
struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
if (log_IsKept(LogDEBUG)) {
@ -103,39 +106,15 @@ p_sockaddr(struct prompt *prompt, struct sockaddr *phost,
switch (phost->sa_family) {
case AF_INET:
if (!phost)
buf[0] = '\0';
else if (ihost4->sin_addr.s_addr == INADDR_ANY)
strcpy(buf, "default");
else if (!pmask)
strcpy(buf, inet_ntoa(ihost4->sin_addr));
else {
u_int32_t msk = ntohl(mask4->sin_addr.s_addr);
u_int32_t tst;
int bits;
int len;
struct sockaddr_in net;
for (tst = 1, bits = 32; tst; tst <<= 1, bits--)
if (msk & tst)
break;
for (tst <<= 1; tst; tst <<= 1)
if (!(msk & tst))
break;
net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr;
strcpy(buf, inet_ntoa(net.sin_addr));
for (len = strlen(buf); len > 3; buf[len -= 2] = '\0')
if (strcmp(buf + len - 2, ".0"))
break;
if (tst) /* non-contiguous :-( */
sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk);
else
sprintf(buf + strlen(buf), "/%d", bits);
}
break;
#ifndef NOINET6
case AF_INET6:
#endif
ncprange_setsa(&range, phost, pmask);
if (ncprange_isdefault(&range))
prompt_Printf(prompt, "%-*s ", width - 1, "default");
else
prompt_Printf(prompt, "%-*s ", width - 1, ncprange_ntoa(&range));
return;
case AF_LINK:
if (dl->sdl_nlen)
@ -160,55 +139,6 @@ p_sockaddr(struct prompt *prompt, struct sockaddr *phost,
sprintf(buf, "link#%d", dl->sdl_index);
break;
#ifndef NOINET6
case AF_INET6:
if (!phost)
buf[0] = '\0';
else {
const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost;
struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask;
int masklen, len;
const u_char *c;
/* XXX: ?????!?!?!!!!! This is horrible ! */
if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) {
ihost6->sin6_scope_id =
ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]);
*(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0;
}
if (mask6) {
const u_char *p, *end;
p = (const u_char *)&mask6->sin6_addr;
end = p + 16;
for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
masklen += 8;
if (p < end) {
for (c = masks; c < masks + sizeof masks; c++)
if (*c == *p) {
masklen += c - masks;
break;
}
}
} else
masklen = 128;
if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr))
snprintf(buf, sizeof buf, "default");
else {
getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf,
NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST);
if (mask6 && (len = strlen(buf)) < sizeof buf - 1)
snprintf(buf + len, sizeof buf - len, "/%d", masklen);
}
}
break;
#endif
default:
sprintf(buf, "<AF type %d>", phost->sa_family);
break;
@ -448,16 +378,13 @@ route_IfDelete(struct bundle *bundle, int all)
{
struct rt_msghdr *rtm;
struct sockaddr *sa[RTAX_MAX];
struct sockaddr_in **in;
struct in_addr sa_none;
struct ncprange range;
int pass;
size_t needed;
char *sp, *cp, *ep;
int mib[6];
log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index);
sa_none.s_addr = INADDR_ANY;
in = (struct sockaddr_in **)sa;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
@ -497,28 +424,37 @@ route_IfDelete(struct bundle *bundle, int all)
for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)cp;
route_ParseHdr(rtm, sa);
if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET) {
log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s),"
" flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
Index2Nam(rtm->rtm_index), rtm->rtm_flags,
inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr));
if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index &&
(all || (rtm->rtm_flags & RTF_GATEWAY))) {
if (sa[RTAX_GATEWAY]->sa_family == AF_INET ||
sa[RTAX_GATEWAY]->sa_family == AF_LINK) {
if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
(pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n",
pass);
rt_Set(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr,
sa_none, sa_none, 0, 0);
} else
log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass);
} else
log_Printf(LogDEBUG,
"route_IfDelete: Can't remove routes of %d family !\n",
sa[RTAX_GATEWAY]->sa_family);
if (rtm->rtm_index == bundle->iface->index &&
sa[RTAX_DST] && sa[RTAX_GATEWAY] &&
(sa[RTAX_DST]->sa_family == AF_INET
#ifndef NOINET6
|| sa[RTAX_DST]->sa_family == AF_INET6
#endif
) &&
(all || (rtm->rtm_flags & RTF_GATEWAY))) {
if (log_IsKept(LogDEBUG)) {
char gwstr[41];
struct ncpaddr gw;
ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]);
ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]);
snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw));
log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr);
}
if (sa[RTAX_GATEWAY]->sa_family == AF_INET ||
#ifndef NOINET6
sa[RTAX_GATEWAY]->sa_family == AF_INET6 ||
#endif
sa[RTAX_GATEWAY]->sa_family == AF_LINK) {
if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
(pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]);
rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0);
} else
log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass);
} else
log_Printf(LogDEBUG,
"route_IfDelete: Can't remove routes for family %d\n",
sa[RTAX_GATEWAY]->sa_family);
}
}
}
@ -534,13 +470,12 @@ route_UpdateMTU(struct bundle *bundle)
{
struct rt_msghdr *rtm;
struct sockaddr *sa[RTAX_MAX];
struct sockaddr_in **in;
struct ncprange dst;
size_t needed;
char *sp, *cp, *ep;
int mib[6];
log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index);
in = (struct sockaddr_in **)sa;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
@ -578,7 +513,8 @@ route_UpdateMTU(struct bundle *bundle)
rtm->rtm_index, Index2Nam(rtm->rtm_index),
inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr),
bundle->iface->mtu);
rt_Update(bundle, in[RTAX_DST]->sin_addr, in[RTAX_GATEWAY]->sin_addr);
ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]);
rt_Update(bundle, &dst);
}
}
@ -602,45 +538,60 @@ GetIfIndex(char *name)
void
route_Change(struct bundle *bundle, struct sticky_route *r,
struct in_addr me, struct in_addr peer, struct in_addr dns[2])
const struct ncpaddr *me, const struct ncpaddr *peer)
{
struct in_addr none, del;
struct ncpaddr dst;
none.s_addr = INADDR_ANY;
for (; r; r = r->next) {
if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) {
del.s_addr = r->dst.s_addr & r->mask.s_addr;
rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0);
r->dst = me;
if (r->type & ROUTE_GWHISADDR)
r->gw = peer;
} else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) {
del.s_addr = r->dst.s_addr & r->mask.s_addr;
rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0);
r->dst = peer;
if (r->type & ROUTE_GWHISADDR)
r->gw = peer;
} else if ((r->type & ROUTE_DSTDNS0) && r->dst.s_addr != peer.s_addr) {
del.s_addr = r->dst.s_addr & r->mask.s_addr;
rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0);
r->dst = dns[0];
if (r->type & ROUTE_GWHISADDR)
r->gw = peer;
} else if ((r->type & ROUTE_DSTDNS1) && r->dst.s_addr != peer.s_addr) {
del.s_addr = r->dst.s_addr & r->mask.s_addr;
rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0);
r->dst = dns[1];
if (r->type & ROUTE_GWHISADDR)
r->gw = peer;
} else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr)
r->gw = peer;
rt_Set(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0);
ncprange_getaddr(&r->dst, &dst);
if (ncpaddr_family(me) == AF_INET) {
if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) {
rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
ncprange_sethost(&r->dst, me);
if (r->type & ROUTE_GWHISADDR)
ncpaddr_copy(&r->gw, peer);
} else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) {
rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
ncprange_sethost(&r->dst, peer);
if (r->type & ROUTE_GWHISADDR)
ncpaddr_copy(&r->gw, peer);
} else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) {
if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE)
continue;
rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
if (r->type & ROUTE_GWHISADDR)
ncpaddr_copy(&r->gw, peer);
} else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) {
if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE)
continue;
rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
if (r->type & ROUTE_GWHISADDR)
ncpaddr_copy(&r->gw, peer);
} else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer))
ncpaddr_copy(&r->gw, peer);
#ifndef NOINET6
} else if (ncpaddr_family(me) == AF_INET6) {
if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) {
rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
ncprange_sethost(&r->dst, me);
if (r->type & ROUTE_GWHISADDR)
ncpaddr_copy(&r->gw, peer);
} else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) {
rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
ncprange_sethost(&r->dst, peer);
if (r->type & ROUTE_GWHISADDR)
ncpaddr_copy(&r->gw, peer);
} else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer))
ncpaddr_copy(&r->gw, peer);
#endif
}
rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0);
}
}
void
route_Add(struct sticky_route **rp, int type, struct in_addr dst,
struct in_addr mask, struct in_addr gw)
route_Add(struct sticky_route **rp, int type, const struct ncprange *dst,
const struct ncpaddr *gw)
{
struct sticky_route *r;
int dsttype = type & ROUTE_DSTANY;
@ -648,7 +599,7 @@ route_Add(struct sticky_route **rp, int type, struct in_addr dst,
r = NULL;
while (*rp) {
if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
(!dsttype && (*rp)->dst.s_addr == dst.s_addr)) {
(!dsttype && ncprange_equal(&(*rp)->dst, dst))) {
/* Oops, we already have this route - unlink it */
free(r); /* impossible really */
r = *rp;
@ -661,21 +612,19 @@ route_Add(struct sticky_route **rp, int type, struct in_addr dst,
r = (struct sticky_route *)malloc(sizeof(struct sticky_route));
r->type = type;
r->next = NULL;
r->dst = dst;
r->mask = mask;
r->gw = gw;
*rp = r;
ncprange_copy(&r->dst, dst);
ncpaddr_copy(&r->gw, gw);
}
void
route_Delete(struct sticky_route **rp, int type, struct in_addr dst)
route_Delete(struct sticky_route **rp, int type, const struct ncprange *dst)
{
struct sticky_route *r;
int dsttype = type & ROUTE_DSTANY;
for (; *rp; rp = &(*rp)->next) {
if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
(!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) {
(!dsttype && ncprange_equal(dst, &(*rp)->dst))) {
r = *rp;
*rp = r->next;
free(r);
@ -700,7 +649,6 @@ void
route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag,
int indent)
{
int def;
int tlen = strlen(tag);
if (tlen + 2 > indent)
@ -709,47 +657,48 @@ route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag,
prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, "");
for (; r; r = r->next) {
def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY;
prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, "");
tlen = 0;
if (r->type & ROUTE_DSTMYADDR)
prompt_Printf(p, "MYADDR");
else if (r->type & ROUTE_DSTMYADDR6)
prompt_Printf(p, "MYADDR6");
else if (r->type & ROUTE_DSTHISADDR)
prompt_Printf(p, "HISADDR");
else if (r->type & ROUTE_DSTHISADDR6)
prompt_Printf(p, "HISADDR6");
else if (r->type & ROUTE_DSTDNS0)
prompt_Printf(p, "DNS0");
else if (r->type & ROUTE_DSTDNS1)
prompt_Printf(p, "DNS1");
else if (!def)
prompt_Printf(p, "%s", inet_ntoa(r->dst));
if (def)
prompt_Printf(p, "default ");
else if (ncprange_isdefault(&r->dst))
prompt_Printf(p, "default");
else
prompt_Printf(p, " %s ", inet_ntoa(r->mask));
prompt_Printf(p, "%s", ncprange_ntoa(&r->dst));
if (r->type & ROUTE_GWHISADDR)
prompt_Printf(p, "HISADDR\n");
prompt_Printf(p, " HISADDR\n");
else if (r->type & ROUTE_GWHISADDR6)
prompt_Printf(p, " HISADDR6\n");
else
prompt_Printf(p, "%s\n", inet_ntoa(r->gw));
prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw));
}
}
struct rtmsg {
struct rt_msghdr m_rtm;
char m_space[64];
char m_space[256];
};
int
rt_Set(struct bundle *bundle, int cmd, struct in_addr dst,
struct in_addr gateway, struct in_addr mask, int bang, int ssh)
rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst,
const struct ncpaddr *gw, int bang, int quiet)
{
struct rtmsg rtmes;
int s, nb, wb;
int domask, s, nb, wb, width;
char *cp;
const char *cmdstr;
struct sockaddr_in rtdata;
struct sockaddr_storage sadst, samask, sagw;
int result = 1;
if (bang)
@ -770,47 +719,50 @@ rt_Set(struct bundle *bundle, int cmd, struct in_addr dst,
rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
if (cmd == RTM_ADD) {
if (bundle->ncp.ipcp.cfg.sendpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe;
if (bundle->ncp.cfg.sendpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe;
rtmes.m_rtm.rtm_inits |= RTV_SPIPE;
}
if (bundle->ncp.ipcp.cfg.recvpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe;
if (bundle->ncp.cfg.recvpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe;
rtmes.m_rtm.rtm_inits |= RTV_RPIPE;
}
}
memset(&rtdata, '\0', sizeof rtdata);
rtdata.sin_len = sizeof rtdata;
rtdata.sin_family = AF_INET;
rtdata.sin_port = 0;
rtdata.sin_addr = dst;
ncprange_getsa(dst, &sadst, &samask);
cp = rtmes.m_space;
memcpy(cp, &rtdata, rtdata.sin_len);
cp += rtdata.sin_len;
memcpy(cp, &sadst, sadst.ss_len);
cp += sadst.ss_len;
if (cmd == RTM_ADD) {
if (gateway.s_addr == INADDR_ANY) {
if (!ssh)
if (gw == NULL) {
log_Printf(LogERROR, "rt_Set: Program error\n");
close(s);
return result;
}
ncpaddr_getsa(gw, &sagw);
if (ncpaddr_isdefault(gw)) {
if (!quiet)
log_Printf(LogERROR, "rt_Set: Cannot add a route with"
" destination 0.0.0.0\n");
close(s);
return result;
} else {
rtdata.sin_addr = gateway;
memcpy(cp, &rtdata, rtdata.sin_len);
cp += rtdata.sin_len;
memcpy(cp, &sagw, sagw.ss_len);
cp += sagw.ss_len;
rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
}
}
if (dst.s_addr == INADDR_ANY)
mask.s_addr = INADDR_ANY;
if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
rtdata.sin_addr = mask;
memcpy(cp, &rtdata, rtdata.sin_len);
cp += rtdata.sin_len;
domask = 1;
if (ncprange_family(dst) == AF_INET) {
ncprange_getwidth(dst, &width);
if (width == 32)
domask = 0;
}
if (domask) {
memcpy(cp, &samask, samask.ss_len);
cp += samask.ss_len;
rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
}
@ -820,16 +772,15 @@ rt_Set(struct bundle *bundle, int cmd, struct in_addr dst,
if (wb < 0) {
log_Printf(LogTCPIP, "rt_Set failure:\n");
log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr);
log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", inet_ntoa(dst));
log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n",
inet_ntoa(gateway));
log_Printf(LogTCPIP, "rt_Set: Mask = %s\n", inet_ntoa(mask));
log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst));
if (gw != NULL)
log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw));
failed:
if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
(rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
if (!bang) {
log_Printf(LogWARN, "Add route failed: %s already exists\n",
dst.s_addr == 0 ? "default" : inet_ntoa(dst));
ncprange_ntoa(dst));
result = 0; /* Don't add to our dynamic list */
} else {
rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
@ -841,29 +792,37 @@ rt_Set(struct bundle *bundle, int cmd, struct in_addr dst,
(rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
if (!bang)
log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
inet_ntoa(dst));
ncprange_ntoa(dst));
} else if (rtmes.m_rtm.rtm_errno == 0) {
if (!ssh || errno != ENETUNREACH)
if (!quiet || errno != ENETUNREACH)
log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
inet_ntoa(dst), strerror(errno));
ncprange_ntoa(dst), strerror(errno));
} else
log_Printf(LogWARN, "%s route failed: %s: %s\n",
cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
}
log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr);
if (log_IsKept(LogDEBUG)) {
char gwstr[40];
if (gw)
snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw));
else
snprintf(gwstr, sizeof gwstr, "<none>");
log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n",
wb, cmdstr, ncprange_ntoa(dst), gwstr);
}
close(s);
return result;
}
void
rt_Update(struct bundle *bundle, struct in_addr dst, struct in_addr gw)
rt_Update(struct bundle *bundle, const struct ncprange *dst)
{
struct rtmsg rtmes;
int s, wb;
struct sockaddr_in rtdata;
struct sockaddr_storage sadst, samask;
s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
if (s < 0) {
@ -879,42 +838,39 @@ rt_Update(struct bundle *bundle, struct in_addr dst, struct in_addr gw)
rtmes.m_rtm.rtm_pid = getpid();
rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
if (bundle->ncp.ipcp.cfg.sendpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe;
if (bundle->ncp.cfg.sendpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe;
rtmes.m_rtm.rtm_inits |= RTV_SPIPE;
}
if (bundle->ncp.ipcp.cfg.recvpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe;
if (bundle->ncp.cfg.recvpipe > 0) {
rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe;
rtmes.m_rtm.rtm_inits |= RTV_RPIPE;
}
rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu;
rtmes.m_rtm.rtm_inits |= RTV_MTU;
memset(&rtdata, '\0', sizeof rtdata);
rtdata.sin_len = sizeof rtdata;
rtdata.sin_family = AF_INET;
rtdata.sin_port = 0;
rtdata.sin_addr = dst;
ncprange_getsa(dst, &sadst, &samask);
memcpy(rtmes.m_space, &rtdata, rtdata.sin_len);
rtmes.m_rtm.rtm_msglen = rtmes.m_space + rtdata.sin_len - (char *)&rtmes;
memcpy(rtmes.m_space, &sadst, sadst.ss_len);
memcpy(rtmes.m_space + sadst.ss_len, &samask, samask.ss_len);
rtmes.m_rtm.rtm_msglen = rtmes.m_space - (char *)&rtmes;
rtmes.m_rtm.rtm_msglen+= sadst.ss_len + samask.ss_len;
wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen);
if (wb < 0) {
log_Printf(LogTCPIP, "rt_Update failure:\n");
log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", inet_ntoa(dst));
log_Printf(LogTCPIP, "rt_Update: Gateway = %s\n", inet_ntoa(gw));
log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", ncprange_ntoa(dst));
if (rtmes.m_rtm.rtm_errno == 0)
log_Printf(LogWARN, "%s: Change route failed: errno: %s\n",
inet_ntoa(dst), strerror(errno));
ncprange_ntoa(dst), strerror(errno));
else
log_Printf(LogWARN, "%s: Change route failed: %s\n",
inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
}
log_Printf(LogDEBUG, "wrote %d: cmd = Change, dst = %x, gateway = %x\n",
wb, (unsigned)dst.s_addr, (unsigned)gw.s_addr);
log_Printf(LogDEBUG, "wrote %d: cmd = Change, dst = %s\n",
wb, ncprange_ntoa(dst));
close(s);
}

View File

@ -33,21 +33,23 @@ struct cmdargs;
struct rt_msghdr;
struct sockaddr;
#define ROUTE_STATIC 0x00
#define ROUTE_DSTMYADDR 0x01
#define ROUTE_DSTHISADDR 0x02
#define ROUTE_DSTDNS0 0x04
#define ROUTE_DSTDNS1 0x08
#define ROUTE_DSTANY 0x0f
#define ROUTE_GWHISADDR 0x10 /* May be ORd with DST_* */
#define ROUTE_STATIC 0x0000
#define ROUTE_DSTMYADDR 0x0001
#define ROUTE_DSTMYADDR6 0x0002
#define ROUTE_DSTHISADDR 0x0004
#define ROUTE_DSTHISADDR6 0x0008
#define ROUTE_DSTDNS0 0x0010
#define ROUTE_DSTDNS1 0x0020
#define ROUTE_DSTANY 0x0040
#define ROUTE_GWHISADDR 0x0080 /* May be ORd with DST_* */
#define ROUTE_GWHISADDR6 0x0100 /* May be ORd with DST_* */
struct sticky_route {
int type; /* ROUTE_* value (not _STATIC) */
struct sticky_route *next; /* next in list */
struct in_addr dst;
struct in_addr mask;
struct in_addr gw;
struct ncprange dst;
struct ncpaddr gw;
};
extern int GetIfIndex(char *);
@ -56,15 +58,15 @@ extern void route_IfDelete(struct bundle *, int);
extern void route_UpdateMTU(struct bundle *);
extern const char *Index2Nam(int);
extern void route_Change(struct bundle *, struct sticky_route *,
struct in_addr, struct in_addr, struct in_addr[2]);
extern void route_Add(struct sticky_route **, int, struct in_addr,
struct in_addr, struct in_addr);
extern void route_Delete(struct sticky_route **, int, struct in_addr);
const struct ncpaddr *, const struct ncpaddr *);
extern void route_Add(struct sticky_route **, int, const struct ncprange *,
const struct ncpaddr *);
extern void route_Delete(struct sticky_route **, int, const struct ncprange *);
extern void route_DeleteAll(struct sticky_route **);
extern void route_Clean(struct bundle *, struct sticky_route *);
extern void route_ShowSticky(struct prompt *, struct sticky_route *,
const char *, int);
extern void route_ParseHdr(struct rt_msghdr *, struct sockaddr *[RTAX_MAX]);
extern int rt_Set(struct bundle *, int, struct in_addr,
struct in_addr, struct in_addr, int, int);
extern void rt_Update(struct bundle *, struct in_addr, struct in_addr);
extern int rt_Set(struct bundle *, int, const struct ncprange *,
const struct ncpaddr *, int, int);
extern void rt_Update(struct bundle *, const struct ncprange *);

View File

@ -45,6 +45,7 @@
#include "server.h"
#include "id.h"
#include "prompt.h"
#include "ncpaddr.h"
static int
server_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
@ -84,19 +85,19 @@ server_IsSet(struct fdescriptor *d, const fd_set *fdset)
return 0;
}
#define IN_SIZE sizeof(struct sockaddr_in)
#define UN_SIZE sizeof(struct sockaddr_un)
#define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE)
static void
server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
{
struct server *s = descriptor2server(d);
char hisaddr[ADDRSZ];
struct sockaddr *sa = (struct sockaddr *)hisaddr;
struct sockaddr_in *in = (struct sockaddr_in *)hisaddr;
int ssize = ADDRSZ, wfd;
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss;
struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
#ifndef NOINET6
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
#endif
int ssize = sizeof ss, wfd;
struct prompt *p;
struct ncpaddr addr;
if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) {
wfd = accept(s->fd, sa, &ssize);
@ -116,18 +117,35 @@ server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
break;
case AF_INET:
if (ntohs(in->sin_port) < 1024) {
ncpaddr_setsa(&addr, sa);
if (ntohs(sin->sin_port) < 1024) {
log_Printf(LogALERT, "Rejected client connection from %s:%u"
"(invalid port number) !\n",
inet_ntoa(in->sin_addr), ntohs(in->sin_port));
ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
close(wfd);
wfd = -1;
break;
}
log_Printf(LogPHASE, "Connected to client from %s:%u\n",
inet_ntoa(in->sin_addr), in->sin_port);
ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
break;
#ifndef NOINET6
case AF_INET6:
ncpaddr_setsa(&addr, sa);
if (ntohs(sin6->sin6_port) < 1024) {
log_Printf(LogALERT, "Rejected client connection from %s:%u"
"(invalid port number) !\n",
ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
close(wfd);
wfd = -1;
break;
}
log_Printf(LogPHASE, "Connected to client from %s:%u\n",
ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
break;
#endif
default:
write(wfd, "Unrecognised access !\n", 22);
close(wfd);
@ -147,10 +165,17 @@ server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
p->src.from[sizeof p->src.from - 1] = '\0';
break;
case AF_INET:
p->src.type = "tcp";
p->src.type = "ip";
snprintf(p->src.from, sizeof p->src.from, "%s:%u",
inet_ntoa(in->sin_addr), in->sin_port);
ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
break;
#ifndef NOINET6
case AF_INET6:
p->src.type = "ip6";
snprintf(p->src.from, sizeof p->src.from, "%s:%u",
ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
break;
#endif
}
prompt_TtyCommandMode(p);
prompt_Required(p);
@ -282,8 +307,13 @@ server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask)
enum server_stat
server_TcpOpen(struct bundle *bundle, u_short port)
{
struct sockaddr_in ifsin;
int s;
struct sockaddr_storage ss;
#ifdef NOINET6
struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
#else
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
#endif
int s, sz;
if (server.cfg.port == port)
server_Close(bundle);
@ -291,17 +321,28 @@ server_TcpOpen(struct bundle *bundle, u_short port)
if (port == 0)
return SERVER_INVALID;
memset(&ss, '\0', sizeof ss);
#ifdef NOINET6
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
sin->sin_len = sizeof ss;
sin->sin_addr.s_addr = INADDR_ANY;
sz = sizeof *sin;
s = socket(PF_INET, SOCK_STREAM, 0);
#else
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
sin6->sin6_len = sizeof ss;
sz = sizeof *sin6;
s = socket(PF_INET6, SOCK_STREAM, 0);
#endif
if (s < 0) {
log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno));
goto failed;
}
memset(&ifsin, '\0', sizeof ifsin);
ifsin.sin_family = AF_INET;
ifsin.sin_addr.s_addr = INADDR_ANY;
ifsin.sin_port = htons(port);
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s);
if (bind(s, (struct sockaddr *)&ifsin, sizeof ifsin) < 0) {
if (bind(s, (struct sockaddr *)&ss, sz) < 0) {
log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno));
close(s);
goto failed;

View File

@ -28,6 +28,7 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
@ -48,6 +49,8 @@
#include "iplist.h"
#include "lqr.h"
#include "hdlc.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "lcp.h"
@ -57,6 +60,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
void

View File

@ -52,6 +52,8 @@
#include "link.h"
#include "iplist.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -60,6 +62,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"

View File

@ -63,6 +63,8 @@
#include "throughput.h"
#include "iplist.h"
#include "slcompress.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "filter.h"
#include "descriptor.h"
@ -74,6 +76,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "tun.h"

View File

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
@ -50,6 +51,8 @@
#include "defs.h"
#include "iplist.h"
#include "throughput.h"
#include "ncpaddr.h"
#include "ip.h"
#include "ipcp.h"
#include "lcp.h"
#include "ccp.h"
@ -60,6 +63,8 @@
#ifndef NORADIUS
#include "radius.h"
#endif
#include "ipv6cp.h"
#include "ncp.h"
#include "bundle.h"
#include "vjcomp.h"