ipcp.c revision 47844
16059Samurai/* 26059Samurai * PPP IP Control Protocol (IPCP) Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2047844Sbrian * $Id: ipcp.c,v 1.80 1999/06/08 11:58:27 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 2346686Sbrian * o Support IPADDRS properly 2446686Sbrian * o Validate the length in IpcpDecodeConfig 256059Samurai */ 2630715Sbrian#include <sys/param.h> 276059Samurai#include <netinet/in_systm.h> 2829048Sbrian#include <netinet/in.h> 296059Samurai#include <netinet/ip.h> 306059Samurai#include <arpa/inet.h> 316059Samurai#include <sys/socket.h> 3240665Sbrian#include <net/route.h> 3330715Sbrian#include <netdb.h> 3436285Sbrian#include <sys/un.h> 3530715Sbrian 3646085Sbrian#include <errno.h> 3736285Sbrian#include <fcntl.h> 3836285Sbrian#include <resolv.h> 3932614Sbrian#include <stdlib.h> 4030715Sbrian#include <string.h> 4136285Sbrian#include <termios.h> 4230715Sbrian#include <unistd.h> 4330715Sbrian 4439395Sbrian#ifndef NOALIAS 4546086Sbrian#ifdef __FreeBSD__ 4646086Sbrian#include <alias.h> 4746086Sbrian#else 4839395Sbrian#include "alias.h" 4939395Sbrian#endif 5039395Sbrian#endif 5146686Sbrian#include "layer.h" 5238814Sbrian#include "ua.h" 5337009Sbrian#include "defs.h" 5431343Sbrian#include "command.h" 5530715Sbrian#include "mbuf.h" 5630715Sbrian#include "log.h" 5730715Sbrian#include "timer.h" 5829048Sbrian#include "fsm.h" 5946686Sbrian#include "proto.h" 6029048Sbrian#include "lcp.h" 6131690Sbrian#include "iplist.h" 6236285Sbrian#include "throughput.h" 6336285Sbrian#include "slcompress.h" 6438557Sbrian#include "lqr.h" 6538557Sbrian#include "hdlc.h" 6629048Sbrian#include "ipcp.h" 6736285Sbrian#include "filter.h" 6836285Sbrian#include "descriptor.h" 6930715Sbrian#include "vjcomp.h" 7036285Sbrian#include "async.h" 7136285Sbrian#include "ccp.h" 7236285Sbrian#include "link.h" 7336285Sbrian#include "physical.h" 7436285Sbrian#include "mp.h" 7543313Sbrian#ifndef NORADIUS 7643313Sbrian#include "radius.h" 7743313Sbrian#endif 7836285Sbrian#include "bundle.h" 7936285Sbrian#include "id.h" 8036285Sbrian#include "arp.h" 8136285Sbrian#include "systems.h" 8236285Sbrian#include "prompt.h" 8331690Sbrian#include "route.h" 8440561Sbrian#include "iface.h" 856059Samurai 8636285Sbrian#undef REJECTED 8736285Sbrian#define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 8836285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t') 8936285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') 906059Samurai 9136285Sbrianstruct compreq { 9236285Sbrian u_short proto; 9336285Sbrian u_char slots; 9436285Sbrian u_char compcid; 9536285Sbrian}; 966059Samurai 9736285Sbrianstatic int IpcpLayerUp(struct fsm *); 9836285Sbrianstatic void IpcpLayerDown(struct fsm *); 9926516Sbrianstatic void IpcpLayerStart(struct fsm *); 10026516Sbrianstatic void IpcpLayerFinish(struct fsm *); 10144305Sbrianstatic void IpcpInitRestartCounter(struct fsm *, int); 10236285Sbrianstatic void IpcpSendConfigReq(struct fsm *); 10336285Sbrianstatic void IpcpSentTerminateReq(struct fsm *); 10436285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char); 10536285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 10636285Sbrian struct fsm_decode *); 1076059Samurai 10836285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = { 1096059Samurai IpcpLayerUp, 1106059Samurai IpcpLayerDown, 1116059Samurai IpcpLayerStart, 1126059Samurai IpcpLayerFinish, 1136059Samurai IpcpInitRestartCounter, 1146059Samurai IpcpSendConfigReq, 11536285Sbrian IpcpSentTerminateReq, 1166059Samurai IpcpSendTerminateAck, 1176059Samurai IpcpDecodeConfig, 11836285Sbrian fsm_NullRecvResetReq, 11936285Sbrian fsm_NullRecvResetAck 1206059Samurai}; 1216059Samurai 12231343Sbrianstatic const char *cftypes[] = { 12331171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 12431171Sbrian "???", 12531171Sbrian "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 12631171Sbrian "COMPPROTO", /* 2: IP-Compression-Protocol */ 12731171Sbrian "IPADDR", /* 3: IP-Address */ 1286059Samurai}; 1296059Samurai 13031962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 13131171Sbrian 13231343Sbrianstatic const char *cftypes128[] = { 13331171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 13431171Sbrian "???", 13531171Sbrian "PRIDNS", /* 129: Primary DNS Server Address */ 13631171Sbrian "PRINBNS", /* 130: Primary NBNS Server Address */ 13731171Sbrian "SECDNS", /* 131: Secondary DNS Server Address */ 13831171Sbrian "SECNBNS", /* 132: Secondary NBNS Server Address */ 13931171Sbrian}; 14031171Sbrian 14131962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 14231171Sbrian 14331272Sbrianvoid 14436285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n) 1456059Samurai{ 14636285Sbrian throughput_addin(&ipcp->throughput, n); 1476059Samurai} 1486059Samurai 14931272Sbrianvoid 15036285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n) 1516059Samurai{ 15236285Sbrian throughput_addout(&ipcp->throughput, n); 1536059Samurai} 1546059Samurai 15536285Sbrianstatic void 15636285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2]) 1576059Samurai{ 15836285Sbrian FILE *fp; 1596059Samurai 16036285Sbrian addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 16136285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 16236285Sbrian char buf[LINE_LEN], *cp, *end; 16336285Sbrian int n; 16436285Sbrian 16536285Sbrian n = 0; 16636285Sbrian buf[sizeof buf - 1] = '\0'; 16736285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 16836285Sbrian if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { 16936285Sbrian for (cp = buf + 11; issep(*cp); cp++) 17036285Sbrian ; 17136285Sbrian for (end = cp; isip(*end); end++) 17236285Sbrian ; 17336285Sbrian *end = '\0'; 17436285Sbrian if (inet_aton(cp, addr+n) && ++n == 2) 17536285Sbrian break; 17636285Sbrian } 17736285Sbrian } 17836285Sbrian if (n == 1) 17936285Sbrian addr[1] = addr[0]; 18036285Sbrian fclose(fp); 18132614Sbrian } 18236285Sbrian} 18329048Sbrian 18436285Sbrianstatic int 18536285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2]) 18636285Sbrian{ 18736285Sbrian FILE *fp; 18836285Sbrian char wbuf[LINE_LEN + 54]; 18936285Sbrian int wlen; 19026516Sbrian 19136285Sbrian if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { 19236285Sbrian struct in_addr old[2]; 19331272Sbrian 19436285Sbrian getdns(ipcp, old); 19536285Sbrian if (addr[0].s_addr == INADDR_ANY) 19636285Sbrian addr[0] = old[0]; 19736285Sbrian if (addr[1].s_addr == INADDR_ANY) 19836285Sbrian addr[1] = old[1]; 19936285Sbrian } 20036285Sbrian 20136285Sbrian if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { 20236285Sbrian log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", 20336285Sbrian _PATH_RESCONF); 20436285Sbrian return 0; 20536285Sbrian } 20636285Sbrian 20736285Sbrian wlen = 0; 20836285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 20936285Sbrian char buf[LINE_LEN]; 21036285Sbrian int len; 21136285Sbrian 21236285Sbrian buf[sizeof buf - 1] = '\0'; 21336285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 21436285Sbrian if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { 21536285Sbrian len = strlen(buf); 21636285Sbrian if (len > sizeof wbuf - wlen) { 21736285Sbrian log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", 21836285Sbrian _PATH_RESCONF, LINE_LEN); 21936285Sbrian fclose(fp); 22036285Sbrian return 0; 22136285Sbrian } 22236285Sbrian memcpy(wbuf + wlen, buf, len); 22336285Sbrian wlen += len; 22436285Sbrian } 22536285Sbrian } 22636285Sbrian fclose(fp); 22736285Sbrian } 22836285Sbrian 22936285Sbrian if (addr[0].s_addr != INADDR_ANY) { 23036285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 23136285Sbrian inet_ntoa(addr[0])); 23236285Sbrian log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); 23336285Sbrian wlen += strlen(wbuf + wlen); 23436285Sbrian } 23536285Sbrian 23636285Sbrian if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { 23736285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 23836285Sbrian inet_ntoa(addr[1])); 23936285Sbrian log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); 24036285Sbrian wlen += strlen(wbuf + wlen); 24136285Sbrian } 24236285Sbrian 24336285Sbrian if (wlen) { 24436285Sbrian int fd; 24536285Sbrian 24636285Sbrian if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { 24736285Sbrian if (write(fd, wbuf, wlen) != wlen) { 24836285Sbrian log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); 24936285Sbrian close(fd); 25036285Sbrian return 0; 25136285Sbrian } 25236285Sbrian if (ftruncate(fd, wlen) == -1) { 25336285Sbrian log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); 25436285Sbrian close(fd); 25536285Sbrian return 0; 25636285Sbrian } 25736285Sbrian close(fd); 25836285Sbrian } else { 25936285Sbrian log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); 26036285Sbrian return 0; 26136285Sbrian } 26236285Sbrian } 26336285Sbrian 26436285Sbrian return 1; 2656059Samurai} 2666059Samurai 26736285Sbrianint 26836285Sbrianipcp_Show(struct cmdargs const *arg) 2696059Samurai{ 27036285Sbrian struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 2716059Samurai 27236285Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 27336285Sbrian State2Nam(ipcp->fsm.state)); 27436285Sbrian if (ipcp->fsm.state == ST_OPENED) { 27536285Sbrian prompt_Printf(arg->prompt, " His side: %s, %s\n", 27636285Sbrian inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 27736285Sbrian prompt_Printf(arg->prompt, " My side: %s, %s\n", 27836285Sbrian inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 2796059Samurai } 28036285Sbrian 28136285Sbrian if (ipcp->route) { 28236285Sbrian prompt_Printf(arg->prompt, "\n"); 28343313Sbrian route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1); 28436285Sbrian } 28536285Sbrian 28636285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 28744305Sbrian prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 28844305Sbrian " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout, 28944305Sbrian ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s", 29044305Sbrian ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s"); 29136285Sbrian prompt_Printf(arg->prompt, " My Address: %s/%d", 29236285Sbrian inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); 29344455Sbrian prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask)); 29436285Sbrian if (ipcp->cfg.HaveTriggerAddress) 29544455Sbrian prompt_Printf(arg->prompt, " Trigger address: %s\n", 29636285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 29744455Sbrian 29844455Sbrian prompt_Printf(arg->prompt, " VJ compression: %s (%d slots %s slot " 29936285Sbrian "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 30036285Sbrian ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 30136285Sbrian 30236285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) 30336285Sbrian prompt_Printf(arg->prompt, " His Address: %s\n", 30436285Sbrian ipcp->cfg.peer_list.src); 30536285Sbrian else 30636285Sbrian prompt_Printf(arg->prompt, " His Address: %s/%d\n", 30736285Sbrian inet_ntoa(ipcp->cfg.peer_range.ipaddr), 30836285Sbrian ipcp->cfg.peer_range.width); 30936285Sbrian 31036285Sbrian prompt_Printf(arg->prompt, " DNS: %s, ", 31136285Sbrian inet_ntoa(ipcp->cfg.ns.dns[0])); 31236285Sbrian prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), 31336285Sbrian command_ShowNegval(ipcp->cfg.ns.dns_neg)); 31436285Sbrian prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", 31536285Sbrian inet_ntoa(ipcp->cfg.ns.nbns[0])); 31636285Sbrian prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); 31736285Sbrian 31836285Sbrian prompt_Printf(arg->prompt, "\n"); 31936285Sbrian throughput_disp(&ipcp->throughput, arg->prompt); 32036285Sbrian 32136285Sbrian return 0; 3226059Samurai} 3236059Samurai 32432614Sbrianint 32536285Sbrianipcp_vjset(struct cmdargs const *arg) 32632614Sbrian{ 32736285Sbrian if (arg->argc != arg->argn+2) 32832614Sbrian return -1; 32936285Sbrian if (!strcasecmp(arg->argv[arg->argn], "slots")) { 33032614Sbrian int slots; 33132614Sbrian 33236285Sbrian slots = atoi(arg->argv[arg->argn+1]); 33332614Sbrian if (slots < 4 || slots > 16) 33432614Sbrian return 1; 33536285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 33632614Sbrian return 0; 33736285Sbrian } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 33836285Sbrian if (!strcasecmp(arg->argv[arg->argn+1], "on")) 33936285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 34036285Sbrian else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 34136285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 34232614Sbrian else 34332614Sbrian return 2; 34432614Sbrian return 0; 34532614Sbrian } 34632614Sbrian return -1; 34732614Sbrian} 34832614Sbrian 34936285Sbrianvoid 35036285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 35136285Sbrian const struct fsm_parent *parent) 35232614Sbrian{ 35336285Sbrian struct hostent *hp; 35436285Sbrian char name[MAXHOSTNAMELEN]; 35536285Sbrian static const char *timer_names[] = 35636285Sbrian {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 35736285Sbrian 35844305Sbrian fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP, 35936285Sbrian bundle, l, parent, &ipcp_Callbacks, timer_names); 36036285Sbrian 36136285Sbrian ipcp->route = NULL; 36236285Sbrian ipcp->cfg.vj.slots = DEF_VJ_STATES; 36336285Sbrian ipcp->cfg.vj.slotcomp = 1; 36436285Sbrian memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 36536285Sbrian if (gethostname(name, sizeof name) == 0) { 36636285Sbrian hp = gethostbyname(name); 36740561Sbrian if (hp && hp->h_addrtype == AF_INET) 36836285Sbrian memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 36932614Sbrian } 37036285Sbrian ipcp->cfg.netmask.s_addr = INADDR_ANY; 37136285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 37236285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, ""); 37336285Sbrian ipcp->cfg.HaveTriggerAddress = 0; 37436285Sbrian 37536285Sbrian ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; 37636285Sbrian ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; 37736285Sbrian ipcp->cfg.ns.dns_neg = 0; 37836285Sbrian ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 37936285Sbrian ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 38036285Sbrian 38144305Sbrian ipcp->cfg.fsm.timeout = DEF_FSMRETRY; 38244305Sbrian ipcp->cfg.fsm.maxreq = DEF_FSMTRIES; 38344305Sbrian ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES; 38436285Sbrian ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 38536285Sbrian 38636285Sbrian memset(&ipcp->vj, '\0', sizeof ipcp->vj); 38736285Sbrian 38836285Sbrian throughput_init(&ipcp->throughput); 38938557Sbrian memset(ipcp->Queue, '\0', sizeof ipcp->Queue); 39043313Sbrian ipcp_Setup(ipcp, INADDR_NONE); 39132614Sbrian} 39232614Sbrian 3936059Samuraivoid 39436285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l) 3956059Samurai{ 39636285Sbrian ipcp->fsm.link = l; 39736285Sbrian} 39836285Sbrian 39936285Sbrianvoid 40043313Sbrianipcp_Setup(struct ipcp *ipcp, u_int32_t mask) 40136285Sbrian{ 40240561Sbrian struct iface *iface = ipcp->fsm.bundle->iface; 40340561Sbrian int pos, n; 40436285Sbrian 40536285Sbrian ipcp->fsm.open_mode = 0; 40643313Sbrian ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask; 40736285Sbrian 40836285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 40940561Sbrian /* Try to give the peer a previously configured IP address */ 41040561Sbrian for (n = 0; n < iface->in_addrs; n++) { 41140561Sbrian pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd); 41240561Sbrian if (pos != -1) { 41340561Sbrian ipcp->cfg.peer_range.ipaddr = 41440561Sbrian iplist_setcurpos(&ipcp->cfg.peer_list, pos); 41540561Sbrian break; 41640561Sbrian } 41740561Sbrian } 41840561Sbrian if (n == iface->in_addrs) 41940561Sbrian /* Ok, so none of 'em fit.... pick a random one */ 42036285Sbrian ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 42140561Sbrian 42236285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 42336285Sbrian ipcp->cfg.peer_range.width = 32; 4246059Samurai } 4259440Samurai 42636285Sbrian ipcp->heis1172 = 0; 42736285Sbrian 42836285Sbrian ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 42936285Sbrian ipcp->peer_compproto = 0; 43036285Sbrian 43136285Sbrian if (ipcp->cfg.HaveTriggerAddress) { 43236285Sbrian /* 43336285Sbrian * Some implementations of PPP require that we send a 43436285Sbrian * *special* value as our address, even though the rfc specifies 43536285Sbrian * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 43636285Sbrian */ 43736285Sbrian ipcp->my_ip = ipcp->cfg.TriggerAddress; 43836285Sbrian log_Printf(LogIPCP, "Using trigger address %s\n", 43936285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 44040561Sbrian } else { 44136285Sbrian /* 44240561Sbrian * Otherwise, if we've used an IP number before and it's still within 44340561Sbrian * the network specified on the ``set ifaddr'' line, we really 44440561Sbrian * want to keep that IP number so that we can keep any existing 44540561Sbrian * connections that are bound to that IP (assuming we're not 44640561Sbrian * ``iface-alias''ing). 44736285Sbrian */ 44840561Sbrian for (n = 0; n < iface->in_addrs; n++) 44940561Sbrian if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) == 45040561Sbrian (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) { 45140561Sbrian ipcp->my_ip = iface->in_addr[n].ifa; 45240561Sbrian break; 45340561Sbrian } 45440561Sbrian if (n == iface->in_addrs) 45540561Sbrian ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 45640561Sbrian } 45736285Sbrian 45843313Sbrian if (IsEnabled(ipcp->cfg.vj.neg) 45943313Sbrian#ifndef NORADIUS 46043313Sbrian || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj) 46143313Sbrian#endif 46243313Sbrian ) 46336285Sbrian ipcp->my_compproto = (PROTO_VJCOMP << 16) + 46436285Sbrian ((ipcp->cfg.vj.slots - 1) << 8) + 46536285Sbrian ipcp->cfg.vj.slotcomp; 46636285Sbrian else 46736285Sbrian ipcp->my_compproto = 0; 46836285Sbrian sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 46936285Sbrian 47036285Sbrian ipcp->peer_reject = 0; 47136285Sbrian ipcp->my_reject = 0; 47236285Sbrian} 47336285Sbrian 47436285Sbrianstatic int 47540665Sbrianipcp_doproxyall(struct bundle *bundle, 47640665Sbrian int (*proxyfun)(struct bundle *, struct in_addr, int), int s) 47740665Sbrian{ 47840665Sbrian int n, ret; 47940665Sbrian struct sticky_route *rp; 48040665Sbrian struct in_addr addr; 48140665Sbrian struct ipcp *ipcp; 48240665Sbrian 48340665Sbrian ipcp = &bundle->ncp.ipcp; 48440665Sbrian for (rp = ipcp->route; rp != NULL; rp = rp->next) { 48544455Sbrian if (rp->mask.s_addr == INADDR_BROADCAST) 48640665Sbrian continue; 48744455Sbrian n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1; 48840665Sbrian if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) { 48940665Sbrian addr = rp->dst; 49040665Sbrian while (n--) { 49140665Sbrian addr.s_addr = htonl(ntohl(addr.s_addr) + 1); 49240665Sbrian log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr)); 49340665Sbrian ret = (*proxyfun)(bundle, addr, s); 49440665Sbrian if (!ret) 49540665Sbrian return ret; 49640665Sbrian } 49740665Sbrian } 49840665Sbrian } 49940665Sbrian 50040665Sbrian return 0; 50140665Sbrian} 50240665Sbrian 50340665Sbrianstatic int 50436285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 50536285Sbrian struct in_addr hisaddr, int silent) 50636285Sbrian{ 50747844Sbrian struct in_addr mask, oaddr, none = { INADDR_ANY }; 50836285Sbrian 50944455Sbrian mask = addr2mask(myaddr); 51036285Sbrian 51143313Sbrian if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY && 51244455Sbrian (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr) 51344455Sbrian mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr; 51436285Sbrian 51540561Sbrian oaddr.s_addr = bundle->iface->in_addrs ? 51640561Sbrian bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY; 51740561Sbrian if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr, 51840561Sbrian IFACE_ADD_FIRST|IFACE_FORCE_ADD)) 51940561Sbrian return -1; 52036285Sbrian 52140561Sbrian if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1 52240561Sbrian && myaddr.s_addr != oaddr.s_addr) 52340561Sbrian /* Nuke the old one */ 52440561Sbrian iface_inDelete(bundle->iface, oaddr); 52536285Sbrian 52640665Sbrian if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0) 52740665Sbrian bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0); 52840665Sbrian 52936285Sbrian if (Enabled(bundle, OPT_SROUTES)) 53036285Sbrian route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 53136285Sbrian 53243313Sbrian#ifndef NORADIUS 53343313Sbrian if (bundle->radius.valid) 53443313Sbrian route_Change(bundle, bundle->radius.routes, myaddr, hisaddr); 53543313Sbrian#endif 53643313Sbrian 53740665Sbrian if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) { 53840561Sbrian int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 53940561Sbrian if (s < 0) 54040561Sbrian log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n", 54140561Sbrian strerror(errno)); 54240561Sbrian else { 54340665Sbrian if (Enabled(bundle, OPT_PROXYALL)) 54440665Sbrian ipcp_doproxyall(bundle, arp_SetProxy, s); 54540665Sbrian else if (Enabled(bundle, OPT_PROXY)) 54640665Sbrian arp_SetProxy(bundle, hisaddr, s); 54740561Sbrian close(s); 54840561Sbrian } 54940561Sbrian } 55036285Sbrian 55140561Sbrian return 0; 5526059Samurai} 5536059Samurai 55436285Sbrianstatic struct in_addr 55540561SbrianChooseHisAddr(struct bundle *bundle, struct in_addr gw) 55636285Sbrian{ 55736285Sbrian struct in_addr try; 55837210Sbrian u_long f; 55936285Sbrian 56036285Sbrian for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 56136285Sbrian try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 56237210Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", 56336285Sbrian f, inet_ntoa(try)); 56436285Sbrian if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 56536285Sbrian log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 56636285Sbrian break; 56736285Sbrian } 56836285Sbrian } 56936285Sbrian 57036285Sbrian if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 57136285Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 57236285Sbrian try.s_addr = INADDR_ANY; 57336285Sbrian } 57436285Sbrian 57536285Sbrian return try; 57636285Sbrian} 57736285Sbrian 5786059Samuraistatic void 57944305SbrianIpcpInitRestartCounter(struct fsm *fp, int what) 5806059Samurai{ 58136285Sbrian /* Set fsm timer load */ 58236285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 58336285Sbrian 58444305Sbrian fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS; 58544305Sbrian switch (what) { 58644305Sbrian case FSM_REQ_TIMER: 58744305Sbrian fp->restart = ipcp->cfg.fsm.maxreq; 58844305Sbrian break; 58944305Sbrian case FSM_TRM_TIMER: 59044305Sbrian fp->restart = ipcp->cfg.fsm.maxtrm; 59144305Sbrian break; 59244305Sbrian default: 59344305Sbrian fp->restart = 1; 59444305Sbrian break; 59544305Sbrian } 5966059Samurai} 5976059Samurai 5986059Samuraistatic void 59936285SbrianIpcpSendConfigReq(struct fsm *fp) 6006059Samurai{ 60136285Sbrian /* Send config REQ please */ 60236285Sbrian struct physical *p = link2physical(fp->link); 60336285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 60436285Sbrian u_char buff[24]; 60536285Sbrian struct lcp_opt *o; 6066059Samurai 60736285Sbrian o = (struct lcp_opt *)buff; 60836285Sbrian 60936285Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 61038814Sbrian memcpy(o->data, &ipcp->my_ip.s_addr, 4); 61136285Sbrian INC_LCP_OPT(TY_IPADDR, 6, o); 61231514Sbrian } 61331514Sbrian 61436285Sbrian if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 61536285Sbrian if (ipcp->heis1172) { 61638814Sbrian u_int16_t proto = PROTO_VJCOMP; 61738814Sbrian 61838814Sbrian ua_htons(&proto, o->data); 61936285Sbrian INC_LCP_OPT(TY_COMPPROTO, 4, o); 62031514Sbrian } else { 62143545Sbrian struct compreq req; 62243545Sbrian 62343545Sbrian req.proto = htons(ipcp->my_compproto >> 16); 62443545Sbrian req.slots = (ipcp->my_compproto >> 8) & 255; 62543545Sbrian req.compcid = ipcp->my_compproto & 1; 62643545Sbrian memcpy(o->data, &req, 4); 62736285Sbrian INC_LCP_OPT(TY_COMPPROTO, 6, o); 62831514Sbrian } 6296059Samurai } 63036285Sbrian 63136285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg) && 63236285Sbrian !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 63336285Sbrian !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 63436285Sbrian struct in_addr dns[2]; 63536285Sbrian getdns(ipcp, dns); 63638814Sbrian memcpy(o->data, &dns[0].s_addr, 4); 63736285Sbrian INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 63838814Sbrian memcpy(o->data, &dns[1].s_addr, 4); 63936285Sbrian INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 64036285Sbrian } 64136285Sbrian 64247695Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 64347695Sbrian MB_IPCPOUT); 6446059Samurai} 6456059Samurai 6466059Samuraistatic void 64744305SbrianIpcpSentTerminateReq(struct fsm *fp) 6486059Samurai{ 64936285Sbrian /* Term REQ just sent by FSM */ 6506059Samurai} 6516059Samurai 6526059Samuraistatic void 65336285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id) 6546059Samurai{ 65536285Sbrian /* Send Term ACK please */ 65647695Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT); 6576059Samurai} 6586059Samurai 6596059Samuraistatic void 66037160SbrianIpcpLayerStart(struct fsm *fp) 6616059Samurai{ 66236285Sbrian /* We're about to start up ! */ 66337160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 66437160Sbrian 66537210Sbrian log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); 66637160Sbrian throughput_start(&ipcp->throughput, "IPCP throughput", 66737160Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 66844305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 6696059Samurai} 6706059Samurai 6716059Samuraistatic void 67236285SbrianIpcpLayerFinish(struct fsm *fp) 6736059Samurai{ 67436285Sbrian /* We're now down */ 67537160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 67637160Sbrian 67737210Sbrian log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); 67837160Sbrian throughput_stop(&ipcp->throughput); 67937160Sbrian throughput_log(&ipcp->throughput, LogIPCP, NULL); 6806059Samurai} 6816059Samurai 68236285Sbrianvoid 68336285Sbrianipcp_CleanInterface(struct ipcp *ipcp) 6846059Samurai{ 68540561Sbrian struct iface *iface = ipcp->fsm.bundle->iface; 68636285Sbrian 68736285Sbrian route_Clean(ipcp->fsm.bundle, ipcp->route); 68836285Sbrian 68940665Sbrian if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) || 69040665Sbrian Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) { 69140561Sbrian int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 69240561Sbrian if (s < 0) 69340561Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", 69440561Sbrian strerror(errno)); 69540561Sbrian else { 69640665Sbrian if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL)) 69740665Sbrian ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s); 69840665Sbrian else if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 69940665Sbrian arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s); 70040561Sbrian close(s); 70140561Sbrian } 70236285Sbrian } 70336285Sbrian 70440561Sbrian iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL); 7056059Samurai} 7066059Samurai 7076059Samuraistatic void 70836285SbrianIpcpLayerDown(struct fsm *fp) 7096059Samurai{ 71036285Sbrian /* About to come down */ 71147835Sbrian static int recursing; 71236285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 71336285Sbrian const char *s; 7146059Samurai 71547835Sbrian if (!recursing++) { 71647835Sbrian if (ipcp->fsm.bundle->iface->in_addrs) 71747835Sbrian s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa); 71847835Sbrian else 71947835Sbrian s = "Interface configuration error !"; 72047835Sbrian log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s); 72130187Sbrian 72247835Sbrian /* 72347835Sbrian * XXX this stuff should really live in the FSM. Our config should 72447835Sbrian * associate executable sections in files with events. 72547835Sbrian */ 72647835Sbrian if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { 72747835Sbrian if (bundle_GetLabel(fp->bundle)) { 72847835Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 72947835Sbrian LINKDOWNFILE, NULL, NULL) < 0) 73047835Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 73147835Sbrian } else 73247835Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 73347835Sbrian } 73447835Sbrian 73547835Sbrian ipcp_Setup(ipcp, INADDR_NONE); 73636285Sbrian } 73747835Sbrian recursing--; 73836285Sbrian} 73936285Sbrian 74036285Sbrianint 74136285Sbrianipcp_InterfaceUp(struct ipcp *ipcp) 74236285Sbrian{ 74336285Sbrian if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 74437019Sbrian log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 74536285Sbrian return 0; 74625630Sbrian } 74736285Sbrian 74831343Sbrian#ifndef NOALIAS 74937191Sbrian if (ipcp->fsm.bundle->AliasEnabled) 75037191Sbrian PacketAliasSetAddress(ipcp->my_ip); 75131343Sbrian#endif 75236285Sbrian 75336285Sbrian return 1; 7546059Samurai} 7556059Samurai 75636285Sbrianstatic int 75736285SbrianIpcpLayerUp(struct fsm *fp) 7586059Samurai{ 75936285Sbrian /* We're now up */ 76036285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 76140561Sbrian char tbuff[16]; 7626059Samurai 76337210Sbrian log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); 76440561Sbrian snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip)); 76540561Sbrian log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n", 76640561Sbrian tbuff, inet_ntoa(ipcp->peer_ip)); 76736285Sbrian 76836285Sbrian if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 76936285Sbrian sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 77036285Sbrian 77136285Sbrian if (!ipcp_InterfaceUp(ipcp)) 77236285Sbrian return 0; 77336285Sbrian 77436285Sbrian /* 77536285Sbrian * XXX this stuff should really live in the FSM. Our config should 77636285Sbrian * associate executable sections in files with events. 77736285Sbrian */ 77840561Sbrian if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 77936285Sbrian if (bundle_GetLabel(fp->bundle)) { 78036285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 78137008Sbrian LINKUPFILE, NULL, NULL) < 0) 78237008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 78336285Sbrian } else 78437008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 78536285Sbrian } 78636285Sbrian 78744305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 78836314Sbrian log_DisplayPrompts(); 78944305Sbrian 79036285Sbrian return 1; 7916059Samurai} 7926059Samurai 7936059Samuraistatic int 79440561SbrianAcceptableAddr(const struct in_range *prange, struct in_addr ipaddr) 7956059Samurai{ 79636285Sbrian /* Is the given IP in the given range ? */ 79725661Sbrian return (prange->ipaddr.s_addr & prange->mask.s_addr) == 79828679Sbrian (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 7996059Samurai} 8006059Samurai 8016059Samuraistatic void 80246828SbrianIpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 80336285Sbrian struct fsm_decode *dec) 8046059Samurai{ 80536285Sbrian /* Deal with incoming PROTO_IPCP */ 80640561Sbrian struct iface *iface = fp->bundle->iface; 80736285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 80840561Sbrian int type, length, gotdns, gotdnsnak, n; 80936285Sbrian u_int32_t compproto; 8106059Samurai struct compreq *pcomp; 81136285Sbrian struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 81236285Sbrian char tbuff[100], tbuff2[100]; 8136059Samurai 81436285Sbrian gotdns = 0; 81536285Sbrian gotdnsnak = 0; 81636285Sbrian dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 8176059Samurai 8186059Samurai while (plen >= sizeof(struct fsmconfig)) { 8196059Samurai type = *cp; 8206059Samurai length = cp[1]; 82136285Sbrian 82236285Sbrian if (length == 0) { 82336285Sbrian log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 82436285Sbrian break; 82536285Sbrian } 82636285Sbrian 82731171Sbrian if (type < NCFTYPES) 82831962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 82931171Sbrian else if (type > 128 && type < 128 + NCFTYPES128) 83031962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 8316059Samurai else 83231962Sbrian snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 8336059Samurai 8346059Samurai switch (type) { 8356059Samurai case TY_IPADDR: /* RFC1332 */ 83638814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 83736285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 8386059Samurai 83931034Sbrian switch (mode_type) { 8406059Samurai case MODE_REQ: 84136285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 84231850Sbrian if (ipaddr.s_addr == INADDR_ANY || 84336285Sbrian iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 84436285Sbrian ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 84536285Sbrian ipaddr, 1)) { 84636285Sbrian log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 84731690Sbrian inet_ntoa(ipaddr)); 84840561Sbrian /* 84940561Sbrian * If we've already had a valid address configured for the peer, 85040561Sbrian * try NAKing with that so that we don't have to upset things 85140561Sbrian * too much. 85240561Sbrian */ 85340561Sbrian for (n = 0; n < iface->in_addrs; n++) 85440561Sbrian if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd) 85540561Sbrian >=0) { 85640561Sbrian ipcp->peer_ip = iface->in_addr[n].brd; 85740561Sbrian break; 85840561Sbrian } 85940561Sbrian 86040561Sbrian if (n == iface->in_addrs) 86136285Sbrian /* Just pick an IP number from our list */ 86236285Sbrian ipcp->peer_ip = ChooseHisAddr 86336285Sbrian (fp->bundle, ipcp->cfg.my_range.ipaddr); 86436285Sbrian 86536285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 86636285Sbrian memcpy(dec->rejend, cp, length); 86736285Sbrian dec->rejend += length; 86831690Sbrian } else { 86936285Sbrian memcpy(dec->nakend, cp, 2); 87040561Sbrian memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 87136285Sbrian dec->nakend += length; 87231690Sbrian } 87331690Sbrian break; 87431690Sbrian } 87536285Sbrian } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 87628679Sbrian /* 87736285Sbrian * If destination address is not acceptable, NAK with what we 87828679Sbrian * want to use. 87928679Sbrian */ 88036285Sbrian memcpy(dec->nakend, cp, 2); 88140561Sbrian for (n = 0; n < iface->in_addrs; n++) 88240561Sbrian if ((iface->in_addr[n].brd.s_addr & 88340561Sbrian ipcp->cfg.peer_range.mask.s_addr) 88440561Sbrian == (ipcp->cfg.peer_range.ipaddr.s_addr & 88540561Sbrian ipcp->cfg.peer_range.mask.s_addr)) { 88640561Sbrian /* We prefer the already-configured address */ 88740561Sbrian memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr, 88840561Sbrian length - 2); 88940561Sbrian break; 89040561Sbrian } 89140561Sbrian 89240561Sbrian if (n == iface->in_addrs) 89340561Sbrian memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 89440561Sbrian 89536285Sbrian dec->nakend += length; 89628679Sbrian break; 8976059Samurai } 89836285Sbrian ipcp->peer_ip = ipaddr; 89936285Sbrian memcpy(dec->ackend, cp, length); 90036285Sbrian dec->ackend += length; 9016059Samurai break; 90240561Sbrian 9036059Samurai case MODE_NAK: 90436285Sbrian if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 90531690Sbrian /* Use address suggested by peer */ 90631962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 90736285Sbrian inet_ntoa(ipcp->my_ip)); 90836285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 90936285Sbrian ipcp->my_ip = ipaddr; 91047648Sbrian bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL); 91131690Sbrian } else { 91236285Sbrian log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 91336285Sbrian "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 91436285Sbrian fsm_Close(&ipcp->fsm); 9156059Samurai } 9166059Samurai break; 91740561Sbrian 9186059Samurai case MODE_REJ: 91936285Sbrian ipcp->peer_reject |= (1 << type); 9206059Samurai break; 9216059Samurai } 9226059Samurai break; 92340561Sbrian 9246059Samurai case TY_COMPPROTO: 92543545Sbrian pcomp = (struct compreq *)(cp + 2); 92643545Sbrian compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 92743545Sbrian pcomp->compcid; 92836285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 9296059Samurai 93031034Sbrian switch (mode_type) { 9316059Samurai case MODE_REQ: 93236285Sbrian if (!IsAccepted(ipcp->cfg.vj.neg)) { 93336285Sbrian memcpy(dec->rejend, cp, length); 93436285Sbrian dec->rejend += length; 9356059Samurai } else { 9366059Samurai switch (length) { 93728679Sbrian case 4: /* RFC1172 */ 9386059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 93943545Sbrian log_Printf(LogWARN, "Peer is speaking RFC1172 compression " 94043545Sbrian "protocol !\n"); 94136285Sbrian ipcp->heis1172 = 1; 94236285Sbrian ipcp->peer_compproto = compproto; 94336285Sbrian memcpy(dec->ackend, cp, length); 94436285Sbrian dec->ackend += length; 9456059Samurai } else { 94636285Sbrian memcpy(dec->nakend, cp, 2); 9476059Samurai pcomp->proto = htons(PROTO_VJCOMP); 94836285Sbrian memcpy(dec->nakend+2, &pcomp, 2); 94936285Sbrian dec->nakend += length; 9506059Samurai } 9516059Samurai break; 95228679Sbrian case 6: /* RFC1332 */ 95343545Sbrian if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 95443545Sbrian if (pcomp->slots <= MAX_VJ_STATES 95543545Sbrian && pcomp->slots >= MIN_VJ_STATES) { 95643545Sbrian /* Ok, we can do that */ 95743545Sbrian ipcp->peer_compproto = compproto; 95843545Sbrian ipcp->heis1172 = 0; 95943545Sbrian memcpy(dec->ackend, cp, length); 96043545Sbrian dec->ackend += length; 96143545Sbrian } else { 96243545Sbrian /* Get as close as we can to what he wants */ 96343545Sbrian ipcp->heis1172 = 0; 96443545Sbrian memcpy(dec->nakend, cp, 2); 96543545Sbrian pcomp->slots = pcomp->slots < MIN_VJ_STATES ? 96643545Sbrian MIN_VJ_STATES : MAX_VJ_STATES; 96743545Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 96843545Sbrian dec->nakend += length; 96943545Sbrian } 9706059Samurai } else { 97143545Sbrian /* What we really want */ 97236285Sbrian memcpy(dec->nakend, cp, 2); 9736059Samurai pcomp->proto = htons(PROTO_VJCOMP); 97436285Sbrian pcomp->slots = DEF_VJ_STATES; 97543545Sbrian pcomp->compcid = 1; 97636285Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 97736285Sbrian dec->nakend += length; 9786059Samurai } 9796059Samurai break; 9806059Samurai default: 98136285Sbrian memcpy(dec->rejend, cp, length); 98236285Sbrian dec->rejend += length; 9836059Samurai break; 9846059Samurai } 9856059Samurai } 9866059Samurai break; 98740561Sbrian 9886059Samurai case MODE_NAK: 98943545Sbrian if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 99043545Sbrian if (pcomp->slots > MAX_VJ_STATES) 99143545Sbrian pcomp->slots = MAX_VJ_STATES; 99243545Sbrian else if (pcomp->slots < MIN_VJ_STATES) 99343545Sbrian pcomp->slots = MIN_VJ_STATES; 99443545Sbrian compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 99543545Sbrian pcomp->compcid; 99643545Sbrian } else 99743545Sbrian compproto = 0; 99836285Sbrian log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 99936285Sbrian tbuff, ipcp->my_compproto, compproto); 100043545Sbrian ipcp->my_compproto = compproto; 10016059Samurai break; 100240561Sbrian 10036059Samurai case MODE_REJ: 100436285Sbrian ipcp->peer_reject |= (1 << type); 10056059Samurai break; 10066059Samurai } 10076059Samurai break; 100840561Sbrian 100928679Sbrian case TY_IPADDRS: /* RFC1172 */ 101038814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 101138814Sbrian memcpy(&dstipaddr.s_addr, cp + 6, 4); 101231962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 101336285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 10146059Samurai 101531034Sbrian switch (mode_type) { 10166059Samurai case MODE_REQ: 101746686Sbrian memcpy(dec->rejend, cp, length); 101846686Sbrian dec->rejend += length; 10196059Samurai break; 102040561Sbrian 10216059Samurai case MODE_NAK: 10226059Samurai case MODE_REJ: 10236059Samurai break; 10246059Samurai } 10256059Samurai break; 102618752Sjkh 102736285Sbrian case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 102836285Sbrian case TY_SECONDARY_DNS: 102938814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 103036285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 103118752Sjkh 103231034Sbrian switch (mode_type) { 103318752Sjkh case MODE_REQ: 103436285Sbrian if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 103536285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 103636285Sbrian memcpy(dec->rejend, cp, length); 103736285Sbrian dec->rejend += length; 103836285Sbrian break; 103936285Sbrian } 104036285Sbrian if (!gotdns) { 104136285Sbrian dns[0] = ipcp->cfg.ns.dns[0]; 104236285Sbrian dns[1] = ipcp->cfg.ns.dns[1]; 104336285Sbrian if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 104436285Sbrian getdns(ipcp, dns); 104536285Sbrian gotdns = 1; 104636285Sbrian } 104736285Sbrian have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 104828679Sbrian 104936285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 105018752Sjkh /* 105136285Sbrian * The client has got the DNS stuff wrong (first request) so 105228974Sbrian * we'll tell 'em how it is 105328679Sbrian */ 105436285Sbrian memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 105536285Sbrian memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 105636285Sbrian dec->nakend += length; 105736285Sbrian } else { 105836285Sbrian /* 105936285Sbrian * Otherwise they have it right (this time) so we send a ack packet 106036285Sbrian * back confirming it... end of story 106136285Sbrian */ 106236285Sbrian memcpy(dec->ackend, cp, length); 106336285Sbrian dec->ackend += length; 106436285Sbrian } 106518752Sjkh break; 106640561Sbrian 106728679Sbrian case MODE_NAK: /* what does this mean?? */ 106836285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 106936285Sbrian gotdnsnak = 1; 107038814Sbrian memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4); 107136285Sbrian } 107218752Sjkh break; 107340561Sbrian 107436285Sbrian case MODE_REJ: /* Can't do much, stop asking */ 107536285Sbrian ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 107618752Sjkh break; 107718752Sjkh } 107818752Sjkh break; 107918752Sjkh 108036285Sbrian case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 108118752Sjkh case TY_SECONDARY_NBNS: 108238814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 108336285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 108436285Sbrian 108531034Sbrian switch (mode_type) { 108618752Sjkh case MODE_REQ: 108736285Sbrian have_ip.s_addr = 108836285Sbrian ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 108936285Sbrian 109036285Sbrian if (have_ip.s_addr == INADDR_ANY) { 109136285Sbrian log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 109236285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 109336285Sbrian memcpy(dec->rejend, cp, length); 109436285Sbrian dec->rejend += length; 109518752Sjkh break; 109636285Sbrian } 109736285Sbrian 109836285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 109936285Sbrian memcpy(dec->nakend, cp, 2); 110036285Sbrian memcpy(dec->nakend+2, &have_ip.s_addr, length); 110136285Sbrian dec->nakend += length; 110236285Sbrian } else { 110336285Sbrian memcpy(dec->ackend, cp, length); 110436285Sbrian dec->ackend += length; 110536285Sbrian } 110618752Sjkh break; 110740561Sbrian 110818752Sjkh case MODE_NAK: 110936285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 111018752Sjkh break; 111140561Sbrian 111218752Sjkh case MODE_REJ: 111336285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 111418752Sjkh break; 111518752Sjkh } 111618752Sjkh break; 111718752Sjkh 11186059Samurai default: 111936285Sbrian if (mode_type != MODE_NOP) { 112036285Sbrian ipcp->my_reject |= (1 << type); 112136285Sbrian memcpy(dec->rejend, cp, length); 112236285Sbrian dec->rejend += length; 112336285Sbrian } 11246059Samurai break; 11256059Samurai } 11266059Samurai plen -= length; 11276059Samurai cp += length; 11286059Samurai } 112936285Sbrian 113036285Sbrian if (gotdnsnak) 113136285Sbrian if (!setdns(ipcp, dnsnak)) { 113236285Sbrian ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 113336285Sbrian ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 113436285Sbrian } 113536285Sbrian 113636285Sbrian if (mode_type != MODE_NOP) { 113736285Sbrian if (dec->rejend != dec->rej) { 113836285Sbrian /* rejects are preferred */ 113936285Sbrian dec->ackend = dec->ack; 114036285Sbrian dec->nakend = dec->nak; 114136285Sbrian } else if (dec->nakend != dec->nak) 114236285Sbrian /* then NAKs */ 114336285Sbrian dec->ackend = dec->ack; 114436285Sbrian } 11456059Samurai} 11466059Samurai 114746686Sbrianextern struct mbuf * 114846686Sbrianipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 11496059Samurai{ 115036285Sbrian /* Got PROTO_IPCP from link */ 115147695Sbrian mbuf_SetType(bp, MB_IPCPIN); 115236285Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 115346686Sbrian fsm_Input(&bundle->ncp.ipcp.fsm, bp); 115436285Sbrian else { 115536285Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 115636285Sbrian log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 115746686Sbrian l->name, bundle_PhaseName(bundle)); 115836285Sbrian mbuf_Free(bp); 115936285Sbrian } 116046686Sbrian return NULL; 11616059Samurai} 116232267Sbrian 116332267Sbrianint 116443313Sbrianipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr) 116543313Sbrian{ 116643313Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 116743313Sbrian 116843313Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 116943313Sbrian iplist_reset(&ipcp->cfg.peer_list); 117043313Sbrian ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr; 117143313Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 117243313Sbrian ipcp->cfg.peer_range.width = 32; 117343313Sbrian 117443313Sbrian if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0) 117543313Sbrian return 0; 117643313Sbrian 117743313Sbrian return 1; /* Ok */ 117843313Sbrian} 117943313Sbrian 118043313Sbrianint 118136285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 118232267Sbrian{ 118336285Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 118436285Sbrian 118536285Sbrian /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 118636285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 118736285Sbrian iplist_reset(&ipcp->cfg.peer_list); 118832267Sbrian if (strpbrk(hisaddr, ",-")) { 118936285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 119036285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 119136285Sbrian iplist_setrandpos(&ipcp->cfg.peer_list); 119236285Sbrian ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 119336285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 119436285Sbrian log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 119547648Sbrian return 0; 119632267Sbrian } 119736285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 119836285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 119936285Sbrian ipcp->cfg.peer_range.width = 32; 120032267Sbrian } else { 120136285Sbrian log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 120232267Sbrian return 0; 120332267Sbrian } 120443313Sbrian } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr, 120536285Sbrian &ipcp->cfg.peer_range.mask, 120636285Sbrian &ipcp->cfg.peer_range.width) != 0) { 120736285Sbrian ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 120832267Sbrian 120936285Sbrian if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 121040561Sbrian ipcp->cfg.peer_range.ipaddr, 0) < 0) 121132267Sbrian return 0; 121232267Sbrian } else 121332267Sbrian return 0; 121432267Sbrian 121547648Sbrian bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip); 121647648Sbrian 121747648Sbrian return 1; /* Ok */ 121832267Sbrian} 121944455Sbrian 122044455Sbrianstruct in_addr 122144455Sbrianaddr2mask(struct in_addr addr) 122244455Sbrian{ 122344455Sbrian u_int32_t haddr = ntohl(addr.s_addr); 122444455Sbrian 122544455Sbrian haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET : 122644455Sbrian IN_CLASSB(haddr) ? IN_CLASSB_NET : 122744455Sbrian IN_CLASSC_NET; 122844455Sbrian addr.s_addr = htonl(haddr); 122944455Sbrian 123044455Sbrian return addr; 123144455Sbrian} 1232