📄 ipcp.c
字号:
if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) return 0; ipcp_script(_PATH_IPPREUP, 1); 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; notice("local IP address %I", wo->ouraddr); notice("remote IP address %I", wo->hisaddr); return 1;}/* * ipcp_up - IPCP has come UP. * * Configure the IP network interface appropriately and bring it up. */static voidipcp_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]; IPCPDEBUG(("ipcp: up")); /* * We must have a non-zero IP address for both ends of the link. */ if (!ho->neg_addr && !ho->old_addrs) ho->hisaddr = wo->hisaddr; if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs) && wo->ouraddr != 0) { error("Peer refused to agree to our IP address"); ipcp_close(f->unit, "Refused our IP address"); return; } if (go->ouraddr == 0) { error("Could not determine local IP address"); ipcp_close(f->unit, "Could not determine local IP address"); return; } if (ho->hisaddr == 0) { ho->hisaddr = htonl(0x0a404040 + ifunit); warn("Could not determine remote IP address: defaulting to %I", ho->hisaddr); } script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); if (go->dnsaddr[0]) script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); if (go->dnsaddr[1]) script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); if (usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { script_setenv("USEPEERDNS", "1", 0); create_resolv(go->dnsaddr[0], go->dnsaddr[1]); } /* * Check that the peer is allowed to use the IP address it wants. */ if (!auth_ip_addr(f->unit, ho->hisaddr)) { error("Peer is not authorized to use remote address %I", 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) { ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr); if (go->ouraddr != wo->ouraddr) { warn("Local IP address changed to %I", go->ouraddr); script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); wo->ouraddr = go->ouraddr; } else script_unsetenv("OLDIPLOCAL"); if (ho->hisaddr != wo->hisaddr) { warn("Remote IP address changed to %I", ho->hisaddr); script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); wo->hisaddr = ho->hisaddr; } else script_unsetenv("OLDIPREMOTE"); /* Set the interface to the new addresses */ mask = GetMask(go->ouraddr); if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { if (debug) warn("Interface configuration 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)) { if (debug) warn("Interface configuration failed"); ipcp_close(f->unit, "Interface configuration failed"); return; }#endif /* run the pre-up script, if any, and wait for it to finish */ ipcp_script(_PATH_IPPREUP, 1); /* bring the interface up for IP */ if (!sifup(f->unit)) { if (debug) warn("Interface failed to come up"); ipcp_close(f->unit, "Interface configuration failed"); return; }#if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { if (debug) warn("Interface configuration 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; ipcp_wantoptions[0].ouraddr = go->ouraddr; notice("local IP address %I", go->ouraddr); notice("remote IP address %I", ho->hisaddr); if (go->dnsaddr[0]) notice("primary DNS address %I", go->dnsaddr[0]); if (go->dnsaddr[1]) notice("secondary DNS address %I", go->dnsaddr[1]); } reset_link_stats(f->unit); np_up(f->unit, PPP_IP); ipcp_is_up = 1; notify(ip_up_notifier, 0); if (ip_up_hook) ip_up_hook(); /* * Execute the ip-up script, like this: * /etc/ppp/ip-up interface tty speed local-IP remote-IP */ if (ipcp_script_state == s_down && ipcp_script_pid == 0) { ipcp_script_state = s_up; ipcp_script(_PATH_IPUP, 0); }}/* * ipcp_down - IPCP has gone DOWN. * * Take the IP network interface down, clear its addresses * and delete routes through it. */static voidipcp_down(f) fsm *f;{ IPCPDEBUG(("ipcp: down")); /* XXX a bit IPv4-centric here, we only need to get the stats * before the interface is marked down. */ /* XXX more correct: we must get the stats before running the notifiers, * at least for the radius plugin */ update_link_stats(f->unit); notify(ip_down_notifier, 0); if (ip_down_hook) ip_down_hook(); if (ipcp_is_up) { ipcp_is_up = 0; np_down(f->unit, PPP_IP); } sifvjcomp(f->unit, 0, 0, 0); print_link_stats(); /* _after_ running the notifiers and ip_down_hook(), * because print_link_stats() sets link_stats_valid * to 0 (zero) */ /* * 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 { sifnpmode(f->unit, PPP_IP, NPMODE_DROP); sifdown(f->unit); ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr, ipcp_hisoptions[f->unit].hisaddr); } /* Execute the ip-down script */ if (ipcp_script_state == s_up && ipcp_script_pid == 0) { ipcp_script_state = s_down; ipcp_script(_PATH_IPDOWN, 0); }}/* * ipcp_clear_addrs() - clear the interface addresses, routes, * proxy arp entries, etc. */static voidipcp_clear_addrs(unit, ouraddr, hisaddr) int unit; u_int32_t ouraddr; /* local address */ u_int32_t hisaddr; /* remote address */{ 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 voidipcp_finished(f) fsm *f;{ if (ipcp_is_open) { ipcp_is_open = 0; np_finished(f->unit, PPP_IP); }}/* * ipcp_script_done - called when the ip-up or ip-down script * has finished. */static voidipcp_script_done(arg) void *arg;{ ipcp_script_pid = 0; switch (ipcp_script_state) { case s_up: if (ipcp_fsm[0].state != OPENED) { ipcp_script_state = s_down; ipcp_script(_PATH_IPDOWN, 0); } break; case s_down: if (ipcp_fsm[0].state == OPENED) { ipcp_script_state = s_up; ipcp_script(_PATH_IPUP, 0); } break; }}/* * ipcp_script - Execute a script with arguments * interface-name tty-name speed local-IP remote-IP. */static voidipcp_script(script, wait) char *script; int wait;{ char strspeed[32], strlocal[32], strremote[32]; char *argv[8]; slprintf(strspeed, sizeof(strspeed), "%d", baud_rate); slprintf(strlocal, sizeof(strlocal), "%I", ipcp_gotoptions[0].ouraddr); slprintf(strremote, sizeof(strremote), "%I", ipcp_hisoptions[0].hisaddr); argv[0] = script; argv[1] = ifname; argv[2] = devnam; argv[3] = strspeed; argv[4] = strlocal; argv[5] = strremote; argv[6] = ipparam; argv[7] = NULL; if (wait) run_program(script, argv, 0, NULL, NULL, 1); else ipcp_script_pid = run_program(script, argv, 0, ipcp_script_done, NULL, 0);}/* * create_resolv - create the replacement resolv.conf file */static voidcreate_resolv(peerdns1, peerdns2) u_int32_t peerdns1, peerdns2;{ FILE *f; f = fopen(_PATH_RESOLV, "w"); if (f == NULL) { error("Failed to create %s: %m", _PATH_RESOLV); return; } if (peerdns1) fprintf(f, "nameserver %s\n", ip_ntoa(peerdns1)); if (peerdns2) fprintf(f, "nameserver %s\n", ip_ntoa(peerdns2)); if (ferror(f)) error("Write failed to %s: %m", _PATH_RESOLV); fclose(f);}/* * ipcp_printpkt - print the contents of an IPCP packet. */static char *ipcp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej"};static intipcp_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%d %I", code - CI_MS_DNS1 + 1, 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((char *)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#ifndef IPPROTO_TCP#define IPPROTO_TCP 6#endif#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 intip_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 + -