📄 ipcp.c
字号:
/* * ipcp.c - PPP IP Control Protocol. * * Copyright (c) 1984-2000 Carnegie Mellon University. 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. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */#define RCSID "$Id: ipcp.c,v 1.70 2005/08/25 23:59:34 paulus Exp $"/* * TODO: */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <netdb.h>#include <sys/param.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "pppd.h"#include "fsm.h"#include "ipcp.h"#include "pathnames.h"static const char rcsid[] = RCSID;/* global vars */ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */u_int32_t netmask = 0; /* IP netmask to set on interface */bool disable_defaultip = 0; /* Don't use hostname for default IP adrs *//* Hook for a plugin to know when IP protocol has come up */void (*ip_up_hook) __P((void)) = NULL;/* Hook for a plugin to know when IP protocol has come down */void (*ip_down_hook) __P((void)) = NULL;/* Hook for a plugin to choose the remote IP address */void (*ip_choose_hook) __P((u_int32_t *)) = NULL;/* Notifiers for when IPCP goes up and down */struct notifier *ip_up_notifier = NULL;struct notifier *ip_down_notifier = NULL;/* local vars */static int default_route_set[NUM_PPP]; /* Have set up a default route */static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */static bool usepeerdns; /* Ask peer for DNS addrs */static int ipcp_is_up; /* have called np_up() */static int ipcp_is_open; /* haven't called np_finished() */static bool ask_for_local; /* request our address from peer */static char vj_value[8]; /* string form of vj option value */static char netmask_str[20]; /* string form of netmask value *//* * Callbacks for fsm code. (CI = Configuration Information) */static void ipcp_resetci __P((fsm *)); /* Reset our CI */static int ipcp_cilen __P((fsm *)); /* Return length of our CI */static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */static int ipcp_nakci __P((fsm *, u_char *, int, int));/* Peer nak'd our CI */static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */static void ipcp_up __P((fsm *)); /* We're UP */static void ipcp_down __P((fsm *)); /* We're DOWN */static void ipcp_finished __P((fsm *)); /* Don't need lower layer */fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ ipcp_resetci, /* Reset our Configuration Information */ ipcp_cilen, /* Length of our Configuration Information */ ipcp_addci, /* Add our Configuration Information */ ipcp_ackci, /* ACK our Configuration Information */ ipcp_nakci, /* NAK our Configuration Information */ ipcp_rejci, /* Reject our Configuration Information */ ipcp_reqci, /* Request peer's Configuration Information */ ipcp_up, /* Called when fsm reaches OPENED state */ ipcp_down, /* Called when fsm leaves OPENED state */ NULL, /* Called when we want the lower layer up */ ipcp_finished, /* Called when we want the lower layer down */ NULL, /* Called when Protocol-Reject received */ NULL, /* Retransmission is necessary */ NULL, /* Called to handle protocol-specific codes */ "IPCP" /* String name of protocol */};/* * Command-line options. */static int setvjslots __P((char **));static int setdnsaddr __P((char **));static int setwinsaddr __P((char **));static int setnetmask __P((char **));int setipaddr __P((char *, char **, int));static void printipaddr __P((option_t *, void (*)(void *, char *,...),void *));static option_t ipcp_option_list[] = { { "noip", o_bool, &ipcp_protent.enabled_flag, "Disable IP and IPCP" }, { "-ip", o_bool, &ipcp_protent.enabled_flag, "Disable IP and IPCP", OPT_ALIAS }, { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, "Disable VJ compression", OPT_ALIAS | OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, "Disable VJ connection-ID compression", OPT_A2CLR, &ipcp_allowoptions[0].cflag }, { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR, &ipcp_allowoptions[0].cflag }, /*/{ "vj-max-slots", o_special, (void *)setvjslots, "Set maximum VJ header slots", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value },*/ { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, "Accept peer's address for us", 1 }, { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote, "Accept peer's address for it", 1 }, { "ipparam", o_string, &ipparam, "Set ip script parameter", OPT_PRIO }, { "noipdefault", o_bool, &disable_defaultip, "Don't use name for default IP adrs", 1 }, { "ms-dns", 1, (void *)setdnsaddr, "DNS address for the peer's use" }, { "ms-wins", 1, (void *)setwinsaddr, "Nameserver for SMB over TCP/IP for peer" }, { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, "Set timeout for IPCP", OPT_PRIO }, { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, "Set max #xmits for term-reqs", OPT_PRIO }, { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, "Set max #xmits for conf-reqs", OPT_PRIO }, { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, "Set max #conf-naks for IPCP", OPT_PRIO }, { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route, "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route }, { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route, "disable defaultroute option", OPT_A2CLR, &ipcp_wantoptions[0].default_route }, { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, &ipcp_wantoptions[0].default_route }, { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp, "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp }, { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, "disable proxyarp option", OPT_A2CLR, &ipcp_wantoptions[0].proxy_arp }, { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, "disable proxyarp option", OPT_ALIAS | OPT_A2CLR, &ipcp_wantoptions[0].proxy_arp }, { "usepeerdns", o_bool, &usepeerdns, "Ask peer for DNS address(es)", 1 }, { "netmask", o_special, (void *)setnetmask, "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, { "ipcp-no-addresses", o_bool, &ipcp_wantoptions[0].old_addrs, "Disable old-style IP-Addresses usage", OPT_A2CLR, &ipcp_allowoptions[0].old_addrs }, { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr, "Disable IP-Address usage", OPT_A2CLR, &ipcp_allowoptions[0].neg_addr }, { "IP addresses", o_wild, (void *) &setipaddr, "set local and remote IP addresses", OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr }, { NULL }};/* * Protocol entry points from main code. */static void ipcp_init __P((int));static void ipcp_open __P((int));static void ipcp_close __P((int, char *));static void ipcp_lowerup __P((int));static void ipcp_lowerdown __P((int));static void ipcp_input __P((int, u_char *, int));static void ipcp_protrej __P((int));static int ipcp_printpkt __P((u_char *, int, void (*) __P((void *, char *, ...)), void *));static void ip_check_options __P((void));static int ip_demand_conf __P((int));static int ip_active_pkt __P((u_char *, int));static void create_resolv __P((u_int32_t, u_int32_t));struct protent ipcp_protent = { PPP_IPCP, ipcp_init, ipcp_input, ipcp_protrej, ipcp_lowerup, ipcp_lowerdown, ipcp_open, ipcp_close, ipcp_printpkt, NULL, 1, "IPCP", "IP", ipcp_option_list, ip_check_options, ip_demand_conf, ip_active_pkt};static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t));static void ipcp_script __P((char *, int)); /* Run an up/down script */static void ipcp_script_done __P((void *));/* * Lengths of configuration options. */#define CILEN_VOID 2#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */#define CILEN_ADDR 6 /* new-style single address option */#define CILEN_ADDRS 10 /* old-style dual address option */#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ (x) == CONFNAK ? "NAK" : "REJ")/* * This state variable is used to ensure that we don't * run an ipcp-up/down script while one is already running. */static enum script_state { s_down, s_up,} ipcp_script_state;static pid_t ipcp_script_pid;/* * Make a string representation of a network IP address. */char *ip_ntoa(ipaddr)u_int32_t ipaddr;{ static char b[64]; slprintf(b, sizeof(b), "%I", ipaddr); return b;}/* * Option parsing. */ #ifdef INCLUDE/* * setvjslots - set maximum number of connection slots for VJ compression */static intsetvjslots(argv) char **argv;{ int value; if (!int_option(*argv, &value)) return 0; if (value < 2 || value > 16) { option_error("vj-max-slots value must be between 2 and 16"); return 0; } ipcp_wantoptions [0].maxslotindex = ipcp_allowoptions[0].maxslotindex = value - 1; slprintf(vj_value, sizeof(vj_value), "%d", value); return 1;}#endif /* INCLUDE *//* * setdnsaddr - set the dns address(es) */static intsetdnsaddr(argv) char **argv;{ u_int32_t dns; struct hostent *hp; dns = inet_addr(*argv); if (dns == (u_int32_t) -1) { if ((hp = gethostbyname(*argv)) == NULL) { option_error("invalid address parameter '%s' for ms-dns option", *argv); return 0; } dns = *(u_int32_t *)hp->h_addr; } /* We take the last 2 values given, the 2nd-last as the primary and the last as the secondary. If only one is given it becomes both primary and secondary. */ if (ipcp_allowoptions[0].dnsaddr[1] == 0) ipcp_allowoptions[0].dnsaddr[0] = dns; else ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1]; /* always set the secondary address value. */ ipcp_allowoptions[0].dnsaddr[1] = dns; return (1);}/* * setwinsaddr - set the wins address(es) * This is primrarly used with the Samba package under UNIX or for pointing * the caller to the existing WINS server on a Windows NT platform. */static intsetwinsaddr(argv) char **argv;{ u_int32_t wins; struct hostent *hp; wins = inet_addr(*argv); if (wins == (u_int32_t) -1) { if ((hp = gethostbyname(*argv)) == NULL) { option_error("invalid address parameter '%s' for ms-wins option", *argv); return 0; } wins = *(u_int32_t *)hp->h_addr; } /* We take the last 2 values given, the 2nd-last as the primary and the last as the secondary. If only one is given it becomes both primary and secondary. */ if (ipcp_allowoptions[0].winsaddr[1] == 0) ipcp_allowoptions[0].winsaddr[0] = wins; else ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1]; /* always set the secondary address value. */ ipcp_allowoptions[0].winsaddr[1] = wins; return (1);}/* * setipaddr - Set the IP address * If doit is 0, the call is to check whether this option is * potentially an IP address specification. * Not static so that plugins can call it to set the addresses */intsetipaddr(arg, argv, doit) char *arg; char **argv; int doit;{ struct hostent *hp; char *colon; u_int32_t local, remote; ipcp_options *wo = &ipcp_wantoptions[0]; static int prio_local = 0, prio_remote = 0; /* * IP address pair separated by ":". */ if ((colon = strchr(arg, ':')) == NULL) return 0; if (!doit) return 1; /* * If colon first character, then no local addr. */ if (colon != arg && option_priority >= prio_local) { *colon = '\0'; if ((local = inet_addr(arg)) == (u_int32_t) -1) { if ((hp = gethostbyname(arg)) == NULL) { option_error("unknown host: %s", arg); return 0; } local = *(u_int32_t *)hp->h_addr; } if (bad_ip_adrs(local)) { option_error("bad local IP address %s", ip_ntoa(local)); return 0; } if (local != 0) wo->ouraddr = local; *colon = ':'; prio_local = option_priority; } /* * If colon last character, then no remote addr. */ if (*++colon != '\0' && option_priority >= prio_remote) { if ((remote = inet_addr(colon)) == (u_int32_t) -1) { if ((hp = gethostbyname(colon)) == NULL) { option_error("unknown host: %s", colon); return 0; } remote = *(u_int32_t *)hp->h_addr; if (remote_name[0] == 0) strlcpy(remote_name, colon, sizeof(remote_name)); } if (bad_ip_adrs(remote)) { option_error("bad remote IP address %s", ip_ntoa(remote)); return 0; } if (remote != 0) wo->hisaddr = remote; prio_remote = option_priority; } return 1;}static voidprintipaddr(opt, printer, arg) option_t *opt; void (*printer) __P((void *, char *, ...)); void *arg;{ ipcp_options *wo = &ipcp_wantoptions[0]; if (wo->ouraddr != 0) printer(arg, "%I", wo->ouraddr); printer(arg, ":"); if (wo->hisaddr != 0) printer(arg, "%I", wo->hisaddr);}/* * setnetmask - set the netmask to be used on the interface. */static intsetnetmask(argv) char **argv;{ u_int32_t mask; int n; char *p; /* * Unfortunately, if we use inet_addr, we can't tell whether * a result of all 1s is an error or a valid 255.255.255.255. */ p = *argv; n = parse_dotted_ip(p, &mask); mask = htonl(mask); if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { option_error("invalid netmask value '%s'", *argv); return 0; } netmask = mask; slprintf(netmask_str, sizeof(netmask_str), "%I", mask); return (1);}intparse_dotted_ip(p, vp) char *p; u_int32_t *vp;{ int n; u_int32_t v, b; char *endp, *p0 = p; v = 0; for (n = 3;; --n) { b = strtoul(p, &endp, 0); if (endp == p) return 0; if (b > 255) { if (n < 3) return 0; /* accept e.g. 0xffffff00 */ *vp = b; return endp - p0; } v |= b << (n * 8); p = endp; if (n == 0) break; if (*p != '.') return 0; ++p; } *vp = v; return p - p0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -