📄 ipcp.c
字号:
/* * ipcp.c - PPP IP Control Protocol. * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Carnegie Mellon University. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#define RCSID "$Id: ipcp.c,v 1.4 2002/09/07 23:07:58 joel Exp $"/* * TODO: */#include <stdio.h>#include <string.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 <resolv.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 */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;/* 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() *//* * 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)); /* 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 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" }, { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, "Disable VJ compression", OPT_A2COPY, &ipcp_allowoptions[0].neg_vj }, { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, "Disable VJ compression", OPT_A2COPY, &ipcp_allowoptions[0].neg_vj }, { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, "Disable VJ connection-ID compression", OPT_A2COPY, &ipcp_allowoptions[0].cflag }, { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, "Disable VJ connection-ID compression", OPT_A2COPY, &ipcp_allowoptions[0].cflag }, { "vj-max-slots", 1, setvjslots, "Set maximum VJ header slots" }, { "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" }, { "noipdefault", o_bool, &disable_defaultip, "Don't use name for default IP adrs", 1 }, { "ms-dns", 1, setdnsaddr, "DNS address for the peer's use" }, { "ms-wins", 1, setwinsaddr, "Nameserver for SMB over TCP/IP for peer" }, { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, "Set timeout for IPCP" }, { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, "Set max #xmits for term-reqs" }, { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, "Set max #xmits for conf-reqs" }, { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, "Set max #conf-naks for IPCP" }, { "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_A2COPY, &ipcp_wantoptions[0].default_route }, { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, "disable defaultroute option", OPT_A2COPY, &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_A2COPY, &ipcp_wantoptions[0].proxy_arp }, { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, "disable proxyarp option", OPT_A2COPY, &ipcp_wantoptions[0].proxy_arp }, { "usepeerdns", o_bool, &usepeerdns, "Ask peer for DNS address(es)", 1 }, { 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));/* * 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")/* * 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. *//* * 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; return 1;}/* * 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; } /* if there is no primary then update it. */ if (ipcp_allowoptions[0].dnsaddr[0] == 0) ipcp_allowoptions[0].dnsaddr[0] = dns; /* always set the secondary address value to the same 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; } /* if there is no primary then update it. */ if (ipcp_allowoptions[0].winsaddr[0] == 0) ipcp_allowoptions[0].winsaddr[0] = wins; /* always set the secondary address value to the same value. */ ipcp_allowoptions[0].winsaddr[1] = wins; return (1);}/* * ipcp_init - Initialize IPCP. */static voidipcp_init(unit) int unit;{ fsm *f = &ipcp_fsm[unit]; ipcp_options *wo = &ipcp_wantoptions[unit]; ipcp_options *ao = &ipcp_allowoptions[unit]; f->unit = unit; f->protocol = PPP_IPCP; f->callbacks = &ipcp_callbacks; fsm_init(&ipcp_fsm[unit]); memset(wo, 0, sizeof(*wo)); memset(ao, 0, sizeof(*ao)); wo->neg_addr = 1; wo->neg_vj = 1; wo->vj_protocol = IPCP_VJ_COMP; wo->maxslotindex = MAX_STATES - 1; /* really max index */ wo->cflag = 1; /* max slots and slot-id compression are currently hardwired in */ /* ppp_if.c to 16 and 1, this needs to be changed (among other */ /* things) gmc */ ao->neg_addr = 1; ao->neg_vj = 1; ao->maxslotindex = MAX_STATES - 1; ao->cflag = 1; /* * XXX These control whether the user may use the proxyarp * and defaultroute options. */ ao->proxy_arp = 1; ao->default_route = 1;}/* * ipcp_open - IPCP is allowed to come up. */static voidipcp_open(unit) int unit;{ fsm_open(&ipcp_fsm[unit]);}/* * ipcp_close - Take IPCP down. */static voidipcp_close(unit, reason) int unit; char *reason;{ fsm_close(&ipcp_fsm[unit], reason);}/* * ipcp_lowerup - The lower layer is up. */static voidipcp_lowerup(unit) int unit;{ fsm_lowerup(&ipcp_fsm[unit]);}/* * ipcp_lowerdown - The lower layer is down. */static voidipcp_lowerdown(unit) int unit;{ fsm_lowerdown(&ipcp_fsm[unit]);}/* * ipcp_input - Input IPCP packet. */static voidipcp_input(unit, p, len) int unit; u_char *p; int len;{ fsm_input(&ipcp_fsm[unit], p, len);}/* * ipcp_protrej - A Protocol-Reject was received for IPCP. * * Pretend the lower layer went down, so we shut up. */static voidipcp_protrej(unit) int unit;{ fsm_lowerdown(&ipcp_fsm[unit]);}/* * ipcp_resetci - Reset our CI. * Called by fsm_sconfreq, Send Configure Request. */static voidipcp_resetci(f) fsm *f;{ ipcp_options *wo = &ipcp_wantoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; if (wo->ouraddr == 0 || disable_defaultip) wo->accept_local = 1; if (wo->hisaddr == 0) wo->accept_remote = 1; wo->req_dns1 = usepeerdns; /* Request DNS addresses from the peer */ wo->req_dns2 = usepeerdns; *go = *wo; if (disable_defaultip) go->ouraddr = 0;}/* * ipcp_cilen - Return length of our CI. * Called by fsm_sconfreq, Send Configure Request. */static intipcp_cilen(f) fsm *f;{ ipcp_options *go = &ipcp_gotoptions[f->unit]; ipcp_options *wo = &ipcp_wantoptions[f->unit]; ipcp_options *ho = &ipcp_hisoptions[f->unit];#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)#define LENCIDNS(neg) (neg ? (CILEN_ADDR) : 0) /* * First see if we want to change our options to the old * forms because we have received old forms from the peer. */ if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { /* use the old style of address negotiation */ go->neg_addr = 1; go->old_addrs = 1; } if (wo->neg_vj && !go->neg_vj && !go->old_vj) { /* try an older style of VJ negotiation */ /* use the old style only if the peer did */ if (ho->neg_vj && ho->old_vj) { go->neg_vj = 1; go->old_vj = 1; go->vj_protocol = ho->vj_protocol; } } return (LENCIADDR(go->neg_addr, go->old_addrs) + LENCIVJ(go->neg_vj, go->old_vj) + LENCIDNS(go->req_dns1) + LENCIDNS(go->req_dns2)) ;}/* * ipcp_addci - Add our desired CIs to a packet. * Called by fsm_sconfreq, Send Configure Request. */static voidipcp_addci(f, ucp, lenp) fsm *f; u_char *ucp; int *lenp;{ ipcp_options *go = &ipcp_gotoptions[f->unit]; int len = *lenp;#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ if (neg) { \ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ if (len >= vjlen) { \ PUTCHAR(opt, ucp); \ PUTCHAR(vjlen, ucp); \ PUTSHORT(val, ucp); \ if (!old) { \ PUTCHAR(maxslotindex, ucp); \ PUTCHAR(cflag, ucp); \ } \ len -= vjlen; \ } else \ neg = 0; \ }#define ADDCIADDR(opt, neg, old, val1, val2) \ if (neg) { \ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ if (len >= addrlen) { \ u_int32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(addrlen, ucp); \ l = ntohl(val1); \ PUTLONG(l, ucp); \ if (old) { \ l = ntohl(val2); \ PUTLONG(l, ucp); \ } \ len -= addrlen; \ } else \ neg = 0; \ }#define ADDCIDNS(opt, neg, addr) \ if (neg) { \ if (len >= CILEN_ADDR) { \ u_int32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_ADDR, ucp); \ l = ntohl(addr); \ PUTLONG(l, ucp); \ len -= CILEN_ADDR; \ } else \ neg = 0; \ } ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, go->old_addrs, go->ouraddr, go->hisaddr); ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); *lenp -= len;}/* * ipcp_ackci - Ack our CIs. * Called by fsm_rconfack, Receive Configure ACK. * * Returns: * 0 - Ack was bad. * 1 - Ack was good. */static intipcp_ackci(f, p, len) fsm *f; u_char *p; int len;{ ipcp_options *go = &ipcp_gotoptions[f->unit]; u_short cilen, citype, cishort; u_int32_t cilong; u_char cimaxslotindex, cicflag; /* * CIs must be in exactly the same order that we sent... * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -