📄 ipcp.c
字号:
if (!reject_if_disagree){
DECPTR(1, p);
PUTCHAR(wo->cflag, p);
}
}
ho->maxslotindex = maxslotindex;
ho->cflag = cflag;
} else {
ho->old_vj = 1;
ho->maxslotindex = MAX_STATES - 1;
ho->cflag = 1;
}
break;
default:
orc = CONFREJ;
break;
}
endswitch:
IPCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
if (orc == CONFACK && /* Good CI */
rc != CONFACK) /* but prior CI wasnt? */
continue; /* Don't send this one */
if (orc == CONFNAK) { /* Nak this CI? */
if (reject_if_disagree) /* Getting fed up with sending NAKs? */
orc = CONFREJ; /* Get tough if so */
else {
if (rc == CONFREJ) /* Rejecting prior CI? */
continue; /* Don't send this one */
if (rc == CONFACK) { /* Ack'd all prior CIs? */
rc = CONFNAK; /* Not anymore... */
ucp = inp; /* Backup */
}
}
}
if (orc == CONFREJ && /* Reject this CI */
rc != CONFREJ) { /* but no prior ones? */
rc = CONFREJ;
ucp = inp; /* Backup */
}
/* Need to move CI? */
if (ucp != cip)
BCOPY(cip, ucp, cilen); /* Move it */
/* Update output pointer */
INCPTR(cilen, ucp);
}
/*
* If we aren't rejecting this packet, and we want to negotiate
* their address, and they didn't send their address, then we
* send a NAK with a CI_ADDR option appended. We assume the
* input buffer is long enough that we can append the extra
* option safely.
*/
if (rc != CONFREJ && !ho->neg_addr &&
wo->req_addr && !reject_if_disagree) {
if (rc == CONFACK) {
rc = CONFNAK;
ucp = inp; /* reset pointer */
wo->req_addr = 0; /* don't ask again */
}
PUTCHAR(CI_ADDR, ucp);
PUTCHAR(CILEN_ADDR, ucp);
tl = ntohl(wo->hisaddr);
PUTLONG(tl, ucp);
}
*len = ucp - inp; /* Compute output length */
IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc)));
return (rc); /* Return final code */
}
/*
* ip_check_options - check that any IP-related options are OK,
* and assign appropriate defaults.
*/
static void
ip_check_options()
{
struct hostent *hp;
u_int32_t local;
ipcp_options *wo = &ipcp_wantoptions[0];
/*
* Default our local IP address based on our hostname.
* If local IP address already given, don't bother.
*/
if (wo->ouraddr == 0 && !disable_defaultip) {
/*
* Look up our hostname (possibly with domain name appended)
* and take the first IP address as our local IP address.
* If there isn't an IP address for our hostname, too bad.
*/
wo->accept_local = 1; /* don't insist on this default value */
if ((hp = gethostbyname(cyg_ppp_hostname)) != NULL) {
local = *(u_int32_t *)hp->h_addr;
if (local != 0 && !bad_ip_adrs(local))
wo->ouraddr = local;
}
}
if (demand && wo->hisaddr == 0) {
option_error("remote IP address required for demand-dialling\n");
}
}
/*
* ip_demand_conf - configure the interface as though
* IPCP were up, for use with dial-on-demand.
*/
static int
ip_demand_conf(u)
int u;
{
ipcp_options *wo = &ipcp_wantoptions[u];
if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
return 0;
if (!sifup(u))
return 0;
if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
return 0;
if (wo->default_route)
if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
default_route_set[u] = 1;
if (wo->proxy_arp)
if (sifproxyarp(u, wo->hisaddr))
proxy_arp_set[u] = 1;
syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(wo->ouraddr));
syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(wo->hisaddr));
return 1;
}
/*
* ipcp_up - IPCP has come UP.
*
* Configure the IP network interface appropriately and bring it up.
*/
static void
ipcp_up(f)
fsm *f;
{
u_int32_t mask;
ipcp_options *ho = &ipcp_hisoptions[f->unit];
ipcp_options *go = &ipcp_gotoptions[f->unit];
ipcp_options *wo = &ipcp_wantoptions[f->unit];
np_up(f->unit, PPP_IP);
IPCPDEBUG((LOG_INFO, "ipcp: up"));
/*
* We must have a non-zero IP address for both ends of the link.
*/
if (!ho->neg_addr)
ho->hisaddr = wo->hisaddr;
if (ho->hisaddr == 0) {
syslog(LOG_ERR, "Could not determine remote IP address");
ipcp_close(f->unit, "Could not determine remote IP address");
return;
}
if (go->ouraddr == 0) {
syslog(LOG_ERR, "Could not determine local IP address");
ipcp_close(f->unit, "Could not determine local IP address");
return;
}
/*
* Check that the peer is allowed to use the IP address it wants.
*/
if (!auth_ip_addr(f->unit, ho->hisaddr)) {
syslog(LOG_ERR, "Peer is not authorized to use remote address %s",
ip_ntoa(ho->hisaddr));
ipcp_close(f->unit, "Unauthorized remote IP address");
return;
}
/* set tcp compression */
sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
/*
* If we are doing dial-on-demand, the interface is already
* configured, so we put out any saved-up packets, then set the
* interface to pass IP packets.
*/
if (demand) {
if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
if (go->ouraddr != wo->ouraddr)
syslog(LOG_WARNING, "Local IP address changed to %s",
ip_ntoa(go->ouraddr));
if (ho->hisaddr != wo->hisaddr)
syslog(LOG_WARNING, "Remote IP address changed to %s",
ip_ntoa(ho->hisaddr));
ipcp_clear_addrs(f->unit);
/* Set the interface to the new addresses */
mask = GetMask(go->ouraddr);
if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
ipcp_close(f->unit, "Interface configuration failed");
return;
}
/* assign a default route through the interface if required */
if (ipcp_wantoptions[f->unit].default_route)
if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
default_route_set[f->unit] = 1;
/* Make a proxy ARP entry if requested. */
if (ipcp_wantoptions[f->unit].proxy_arp)
if (sifproxyarp(f->unit, ho->hisaddr))
proxy_arp_set[f->unit] = 1;
}
demand_rexmit(PPP_IP);
sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
} else {
/*
* Set IP addresses and (if specified) netmask.
*/
mask = GetMask(go->ouraddr);
#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
ipcp_close(f->unit, "Interface configuration failed");
return;
}
#endif
/* bring the interface up for IP */
if (!sifup(f->unit)) {
IPCPDEBUG((LOG_WARNING, "sifup failed"));
ipcp_close(f->unit, "Interface configuration failed");
return;
}
#if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
ipcp_close(f->unit, "Interface configuration failed");
return;
}
#endif
sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
/* assign a default route through the interface if required */
if (ipcp_wantoptions[f->unit].default_route)
if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
default_route_set[f->unit] = 1;
/* Make a proxy ARP entry if requested. */
if (ipcp_wantoptions[f->unit].proxy_arp)
if (sifproxyarp(f->unit, ho->hisaddr))
proxy_arp_set[f->unit] = 1;
syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr));
syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
}
}
/*
* ipcp_down - IPCP has gone DOWN.
*
* Take the IP network interface down, clear its addresses
* and delete routes through it.
*/
static void
ipcp_down(f)
fsm *f;
{
IPCPDEBUG((LOG_INFO, "ipcp: down"));
np_down(f->unit, PPP_IP);
sifvjcomp(f->unit, 0, 0, 0);
/*
* If we are doing dial-on-demand, set the interface
* to queue up outgoing packets (for now).
*/
if (demand) {
sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE);
} else {
sifdown(f->unit);
ipcp_clear_addrs(f->unit);
}
}
/*
* ipcp_clear_addrs() - clear the interface addresses, routes,
* proxy arp entries, etc.
*/
static void
ipcp_clear_addrs(unit)
int unit;
{
u_int32_t ouraddr, hisaddr;
ouraddr = ipcp_gotoptions[unit].ouraddr;
hisaddr = ipcp_hisoptions[unit].hisaddr;
if (proxy_arp_set[unit]) {
cifproxyarp(unit, hisaddr);
proxy_arp_set[unit] = 0;
}
if (default_route_set[unit]) {
cifdefaultroute(unit, ouraddr, hisaddr);
default_route_set[unit] = 0;
}
cifaddr(unit, ouraddr, hisaddr);
}
/*
* ipcp_finished - possibly shut down the lower layers.
*/
static void
ipcp_finished(f)
fsm *f;
{
np_finished(f->unit, PPP_IP);
}
/*
* ipcp_printpkt - print the contents of an IPCP packet.
*/
static char *ipcp_codenames[] = {
"ConfReq", "ConfAck", "ConfNak", "ConfRej",
"TermReq", "TermAck", "CodeRej"
};
static int
ipcp_printpkt(p, plen, printer, arg)
u_char *p;
int plen;
void (*printer) __P((void *, char *, ...));
void *arg;
{
int code, id, len, olen;
u_char *pstart, *optend;
u_short cishort;
u_int32_t cilong;
if (plen < HEADERLEN)
return 0;
pstart = p;
GETCHAR(code, p);
GETCHAR(id, p);
GETSHORT(len, p);
if (len < HEADERLEN || len > plen)
return 0;
if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
printer(arg, " %s", ipcp_codenames[code-1]);
else
printer(arg, " code=0x%x", code);
printer(arg, " id=0x%x", id);
len -= HEADERLEN;
switch (code) {
case CONFREQ:
case CONFACK:
case CONFNAK:
case CONFREJ:
/* print option list */
while (len >= 2) {
GETCHAR(code, p);
GETCHAR(olen, p);
p -= 2;
if (olen < 2 || olen > len) {
break;
}
printer(arg, " <");
len -= olen;
optend = p + olen;
switch (code) {
case CI_ADDRS:
if (olen == CILEN_ADDRS) {
p += 2;
GETLONG(cilong, p);
printer(arg, "addrs %I", htonl(cilong));
GETLONG(cilong, p);
printer(arg, " %I", htonl(cilong));
}
break;
case CI_COMPRESSTYPE:
if (olen >= CILEN_COMPRESS) {
p += 2;
GETSHORT(cishort, p);
printer(arg, "compress ");
switch (cishort) {
case IPCP_VJ_COMP:
printer(arg, "VJ");
break;
case IPCP_VJ_COMP_OLD:
printer(arg, "old-VJ");
break;
default:
printer(arg, "0x%x", cishort);
}
}
break;
case CI_ADDR:
if (olen == CILEN_ADDR) {
p += 2;
GETLONG(cilong, p);
printer(arg, "addr %I", htonl(cilong));
}
break;
case CI_MS_DNS1:
case CI_MS_DNS2:
p += 2;
GETLONG(cilong, p);
printer(arg, "ms-dns %I", htonl(cilong));
break;
case CI_MS_WINS1:
case CI_MS_WINS2:
p += 2;
GETLONG(cilong, p);
printer(arg, "ms-wins %I", htonl(cilong));
break;
}
while (p < optend) {
GETCHAR(code, p);
printer(arg, " %.2x", code);
}
printer(arg, ">");
}
break;
case TERMACK:
case TERMREQ:
if (len > 0 && *p >= ' ' && *p < 0x7f) {
printer(arg, " ");
print_string(p, len, printer, arg);
p += len;
len = 0;
}
break;
}
/* print the rest of the bytes in the packet */
for (; len > 0; --len) {
GETCHAR(code, p);
printer(arg, " %.2x", code);
}
return p - pstart;
}
/*
* ip_active_pkt - see if this IP packet is worth bringing the link up for.
* We don't bring the link up for IP fragments or for TCP FIN packets
* with no data.
*/
#define IP_HDRLEN 20 /* bytes */
#define IP_OFFMASK 0x1fff
#define IPPROTO_TCP 6
#define TCP_HDRLEN 20
#define TH_FIN 0x01
/*
* We use these macros because the IP header may be at an odd address,
* and some compilers might use word loads to get th_off or ip_hl.
*/
#define net_short(x) (((x)[0] << 8) + (x)[1])
#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF)
#define get_ipoff(x) net_short((unsigned char *)(x) + 6)
#define get_ipproto(x) (((unsigned char *)(x))[9])
#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
#define get_tcpflags(x) (((unsigned char *)(x))[13])
static int
ip_active_pkt(pkt, len)
u_char *pkt;
int len;
{
u_char *tcp;
int hlen;
len -= PPP_HDRLEN;
pkt += PPP_HDRLEN;
if (len < IP_HDRLEN)
return 0;
if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
return 0;
if (get_ipproto(pkt) != IPPROTO_TCP)
return 1;
hlen = get_iphl(pkt) * 4;
if (len < hlen + TCP_HDRLEN)
return 0;
tcp = pkt + hlen;
if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
return 0;
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -