ipcp.c revision 31034
1/* 2 * PPP IP Control Protocol (IPCP) Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: ipcp.c,v 1.33 1997/10/29 01:19:40 brian Exp $ 21 * 22 * TODO: 23 * o More RFC1772 backwoard compatibility 24 */ 25#include <sys/param.h> 26#include <netinet/in_systm.h> 27#include <netinet/in.h> 28#include <netinet/ip.h> 29#include <arpa/inet.h> 30#include <sys/socket.h> 31#include <netdb.h> 32 33#include <limits.h> 34#include <stdio.h> 35#include <string.h> 36#include <unistd.h> 37 38#include "mbuf.h" 39#include "log.h" 40#include "defs.h" 41#include "timer.h" 42#include "fsm.h" 43#include "lcpproto.h" 44#include "lcp.h" 45#include "ipcp.h" 46#include "slcompress.h" 47#include "os.h" 48#include "phase.h" 49#include "loadalias.h" 50#include "command.h" 51#include "vars.h" 52#include "vjcomp.h" 53#include "ip.h" 54 55#ifndef NOMSEXT 56struct in_addr ns_entries[2]; 57struct in_addr nbns_entries[2]; 58#endif 59 60struct ipcpstate IpcpInfo; 61struct in_range DefMyAddress; 62struct in_range DefHisAddress; 63struct in_addr TriggerAddress; 64int HaveTriggerAddress; 65struct pppTimer IpcpReportTimer; 66 67static void IpcpSendConfigReq(struct fsm *); 68static void IpcpSendTerminateAck(struct fsm *); 69static void IpcpSendTerminateReq(struct fsm *); 70static void IpcpDecodeConfig(u_char *, int, int); 71static void IpcpLayerStart(struct fsm *); 72static void IpcpLayerFinish(struct fsm *); 73static void IpcpLayerUp(struct fsm *); 74static void IpcpLayerDown(struct fsm *); 75static void IpcpInitRestartCounter(struct fsm *); 76static int IpcpOctetsIn(void); 77static int IpcpOctetsOut(void); 78 79static int lastInOctets, lastOutOctets; 80static int StartingIpIn, StartingIpOut; 81 82#define REJECTED(p, x) (p->his_reject & (1<<x)) 83 84struct fsm IpcpFsm = { 85 "IPCP", 86 PROTO_IPCP, 87 IPCP_MAXCODE, 88 OPEN_ACTIVE, 89 ST_INITIAL, 90 0, 0, 0, 91 92 0, 93 {0, 0, 0, NULL, NULL, NULL}, 94 {0, 0, 0, NULL, NULL, NULL}, 95 LogIPCP, 96 97 IpcpLayerUp, 98 IpcpLayerDown, 99 IpcpLayerStart, 100 IpcpLayerFinish, 101 IpcpInitRestartCounter, 102 IpcpSendConfigReq, 103 IpcpSendTerminateReq, 104 IpcpSendTerminateAck, 105 IpcpDecodeConfig, 106}; 107 108static char *cftypes[] = { 109 "???", "IPADDRS", "COMPPROTO", "IPADDR", 110}; 111 112/* 113 * Function called every second. Updates connection period and idle period, 114 * also update LQR information. 115 */ 116static void 117IpcpReportFunc() 118{ 119 ipConnectSecs++; 120 if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets) 121 ipIdleSecs++; 122 lastInOctets = ipInOctets; 123 lastOutOctets = ipOutOctets; 124 StopTimer(&IpcpReportTimer); 125 IpcpReportTimer.state = TIMER_STOPPED; 126 StartTimer(&IpcpReportTimer); 127} 128 129static void 130IpcpStartReport() 131{ 132 ipIdleSecs = ipConnectSecs = 0; 133 StopTimer(&IpcpReportTimer); 134 IpcpReportTimer.state = TIMER_STOPPED; 135 IpcpReportTimer.load = SECTICKS; 136 IpcpReportTimer.func = IpcpReportFunc; 137 StartTimer(&IpcpReportTimer); 138} 139 140int 141ReportIpcpStatus() 142{ 143 struct ipcpstate *icp = &IpcpInfo; 144 struct fsm *fp = &IpcpFsm; 145 146 if (!VarTerm) 147 return 1; 148 fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]); 149 fprintf(VarTerm, " his side: %s, %lx\n", 150 inet_ntoa(icp->his_ipaddr), icp->his_compproto); 151 fprintf(VarTerm, " my side: %s, %lx\n", 152 inet_ntoa(icp->want_ipaddr), icp->want_compproto); 153 fprintf(VarTerm, "Connected: %d secs, idle: %d secs\n\n", 154 ipConnectSecs, ipIdleSecs); 155 fprintf(VarTerm, " %d octets in, %d octets out\n", 156 IpcpOctetsIn(), IpcpOctetsOut()); 157 158 fprintf(VarTerm, "Defaults:\n"); 159 fprintf(VarTerm, " My Address: %s/%d\n", 160 inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); 161 fprintf(VarTerm, " His Address: %s/%d\n", 162 inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); 163 if (HaveTriggerAddress) 164 fprintf(VarTerm, " Negotiation(trigger): %s\n", inet_ntoa(TriggerAddress)); 165 else 166 fprintf(VarTerm, " Negotiation(trigger): MYADDR\n"); 167 168 return 0; 169} 170 171void 172IpcpDefAddress() 173{ 174 struct hostent *hp; 175 char name[200]; 176 177 memset(&DefMyAddress, '\0', sizeof(DefMyAddress)); 178 memset(&DefHisAddress, '\0', sizeof(DefHisAddress)); 179 TriggerAddress.s_addr = 0; 180 HaveTriggerAddress = 0; 181 if (gethostname(name, sizeof(name)) == 0) { 182 hp = gethostbyname(name); 183 if (hp && hp->h_addrtype == AF_INET) { 184 memcpy(&DefMyAddress.ipaddr.s_addr, hp->h_addr, hp->h_length); 185 } 186 } 187} 188 189void 190IpcpInit() 191{ 192 struct ipcpstate *icp = &IpcpInfo; 193 194 FsmInit(&IpcpFsm); 195 memset(icp, '\0', sizeof(struct ipcpstate)); 196 if ((mode & MODE_DEDICATED) && !dstsystem) { 197 icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; 198 } else { 199 icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; 200 icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; 201 } 202 203 /* 204 * Some implementations of PPP require that we send a 205 * *special* value as our address, even though the rfc specifies 206 * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 207 */ 208 if (HaveTriggerAddress) { 209 icp->want_ipaddr.s_addr = TriggerAddress.s_addr; 210 LogPrintf(LogIPCP, "Using trigger address %s\n", inet_ntoa(TriggerAddress)); 211 } 212 if (Enabled(ConfVjcomp)) 213 icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8) | 1; 214 else 215 icp->want_compproto = 0; 216 icp->heis1172 = 0; 217 IpcpFsm.maxconfig = 10; 218 StartingIpIn = ipInOctets; 219 StartingIpOut = ipOutOctets; 220} 221 222static void 223IpcpInitRestartCounter(struct fsm * fp) 224{ 225 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 226 fp->restart = 5; 227} 228 229static void 230IpcpSendConfigReq(struct fsm * fp) 231{ 232 u_char *cp; 233 struct ipcpstate *icp = &IpcpInfo; 234 235 cp = ReqBuff; 236 LogPrintf(LogIPCP, "IpcpSendConfigReq\n"); 237 if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) 238 PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr)); 239 if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { 240 if (icp->heis1172) 241 PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16); 242 else 243 PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); 244 } 245 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 246} 247 248static void 249IpcpSendTerminateReq(struct fsm * fp) 250{ 251 /* XXX: No code yet */ 252} 253 254static void 255IpcpSendTerminateAck(struct fsm * fp) 256{ 257 LogPrintf(LogIPCP, "IpcpSendTerminateAck\n"); 258 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 259} 260 261static void 262IpcpLayerStart(struct fsm * fp) 263{ 264 LogPrintf(LogIPCP, "IpcpLayerStart.\n"); 265} 266 267static void 268IpcpLayerFinish(struct fsm * fp) 269{ 270 LogPrintf(LogIPCP, "IpcpLayerFinish.\n"); 271 reconnect(RECON_FALSE); 272 LcpClose(); 273 NewPhase(PHASE_TERMINATE); 274} 275 276static int 277IpcpOctetsIn() 278{ 279 return ipInOctets < StartingIpIn ? 280 INT_MAX - StartingIpIn + ipInOctets - INT_MIN + 1 : 281 ipInOctets - StartingIpIn; 282} 283 284static int 285IpcpOctetsOut() 286{ 287 return ipOutOctets < StartingIpOut ? 288 INT_MAX - StartingIpOut + ipOutOctets - INT_MIN + 1 : 289 ipOutOctets - StartingIpOut; 290} 291 292static void 293IpcpLayerDown(struct fsm * fp) 294{ 295 LogPrintf(LogIPCP, "IpcpLayerDown.\n"); 296 LogPrintf(LogIPCP, "%d octets in, %d octets out\n", 297 IpcpOctetsIn(), IpcpOctetsOut()); 298 StopTimer(&IpcpReportTimer); 299 Prompt(); 300} 301 302/* 303 * Called when IPCP has reached to OPEN state 304 */ 305static void 306IpcpLayerUp(struct fsm * fp) 307{ 308 char tbuff[100]; 309 310 Prompt(); 311 LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state); 312 snprintf(tbuff, sizeof(tbuff), "myaddr = %s ", 313 inet_ntoa(IpcpInfo.want_ipaddr)); 314 315 if (IpcpInfo.his_compproto >> 16 == PROTO_VJCOMP) 316 VjInit((IpcpInfo.his_compproto >> 8) & 255); 317 318 LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n", 319 tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 320 if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask) < 0) { 321 if (VarTerm) 322 LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n"); 323 return; 324 } 325 if (mode & MODE_ALIAS) 326 VarPacketAliasSetAddress(IpcpInfo.want_ipaddr); 327 OsLinkup(); 328 StartingIpIn = ipInOctets; 329 StartingIpOut = ipOutOctets; 330 IpcpStartReport(); 331 StartIdleTimer(); 332} 333 334void 335IpcpUp() 336{ 337 FsmUp(&IpcpFsm); 338 LogPrintf(LogIPCP, "IPCP Up event!!\n"); 339} 340 341void 342IpcpOpen() 343{ 344 FsmOpen(&IpcpFsm); 345} 346 347static int 348AcceptableAddr(struct in_range * prange, struct in_addr ipaddr) 349{ 350 LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr)); 351 LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr)); 352 LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr)); 353 LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange-> 354 mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr)); 355 return (prange->ipaddr.s_addr & prange->mask.s_addr) == 356 (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 357} 358 359static void 360IpcpDecodeConfig(u_char * cp, int plen, int mode_type) 361{ 362 int type, length; 363 u_long *lp, compproto; 364 struct compreq *pcomp; 365 struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req; 366 char tbuff[100]; 367 char tbuff2[100]; 368 369 ackp = AckBuff; 370 nakp = NakBuff; 371 rejp = RejBuff; 372 373 while (plen >= sizeof(struct fsmconfig)) { 374 type = *cp; 375 length = cp[1]; 376 if (type <= TY_IPADDR) 377 snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length); 378 else 379 snprintf(tbuff, sizeof(tbuff), " "); 380 381 switch (type) { 382 case TY_IPADDR: /* RFC1332 */ 383 lp = (u_long *) (cp + 2); 384 ipaddr.s_addr = *lp; 385 LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 386 387 switch (mode_type) { 388 case MODE_REQ: 389 if (!AcceptableAddr(&DefHisAddress, ipaddr)) { 390 /* 391 * If destination address is not acceptable, insist to use what we 392 * want to use. 393 */ 394 memcpy(nakp, cp, 2); 395 memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length); 396 nakp += length; 397 break; 398 } 399 IpcpInfo.his_ipaddr = ipaddr; 400 memcpy(ackp, cp, length); 401 ackp += length; 402 break; 403 case MODE_NAK: 404 if (AcceptableAddr(&DefMyAddress, ipaddr)) { 405 406 /* 407 * Use address suggested by peer. 408 */ 409 snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s ", tbuff, 410 inet_ntoa(IpcpInfo.want_ipaddr)); 411 LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 412 IpcpInfo.want_ipaddr = ipaddr; 413 } 414 break; 415 case MODE_REJ: 416 IpcpInfo.his_reject |= (1 << type); 417 break; 418 } 419 break; 420 case TY_COMPPROTO: 421 lp = (u_long *) (cp + 2); 422 compproto = htonl(*lp); 423 LogPrintf(LogIPCP, "%s %08x\n", tbuff, compproto); 424 425 switch (mode_type) { 426 case MODE_REQ: 427 if (!Acceptable(ConfVjcomp)) { 428 memcpy(rejp, cp, length); 429 rejp += length; 430 } else { 431 pcomp = (struct compreq *) (cp + 2); 432 switch (length) { 433 case 4: /* RFC1172 */ 434 if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 435 LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); 436 IpcpInfo.heis1172 = 1; 437 IpcpInfo.his_compproto = compproto; 438 memcpy(ackp, cp, length); 439 ackp += length; 440 } else { 441 memcpy(nakp, cp, 2); 442 pcomp->proto = htons(PROTO_VJCOMP); 443 memcpy(nakp+2, &pcomp, 2); 444 nakp += length; 445 } 446 break; 447 case 6: /* RFC1332 */ 448 if (ntohs(pcomp->proto) == PROTO_VJCOMP 449 && pcomp->slots < MAX_STATES && pcomp->slots > 2) { 450 IpcpInfo.his_compproto = compproto; 451 IpcpInfo.heis1172 = 0; 452 memcpy(ackp, cp, length); 453 ackp += length; 454 } else { 455 memcpy(nakp, cp, 2); 456 pcomp->proto = htons(PROTO_VJCOMP); 457 pcomp->slots = MAX_STATES - 1; 458 pcomp->compcid = 0; 459 memcpy(nakp+2, &pcomp, sizeof(pcomp)); 460 nakp += length; 461 } 462 break; 463 default: 464 memcpy(rejp, cp, length); 465 rejp += length; 466 break; 467 } 468 } 469 break; 470 case MODE_NAK: 471 LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 472 tbuff, IpcpInfo.want_compproto, compproto); 473 IpcpInfo.want_compproto = compproto; 474 break; 475 case MODE_REJ: 476 IpcpInfo.his_reject |= (1 << type); 477 break; 478 } 479 break; 480 case TY_IPADDRS: /* RFC1172 */ 481 lp = (u_long *) (cp + 2); 482 ipaddr.s_addr = *lp; 483 lp = (u_long *) (cp + 6); 484 dstipaddr.s_addr = *lp; 485 snprintf(tbuff2, sizeof(tbuff2), "%s %s,", tbuff, inet_ntoa(ipaddr)); 486 LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 487 488 switch (mode_type) { 489 case MODE_REQ: 490 IpcpInfo.his_ipaddr = ipaddr; 491 IpcpInfo.want_ipaddr = dstipaddr; 492 memcpy(ackp, cp, length); 493 ackp += length; 494 break; 495 case MODE_NAK: 496 snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s", tbuff, 497 inet_ntoa(IpcpInfo.want_ipaddr)); 498 LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 499 IpcpInfo.want_ipaddr = ipaddr; 500 IpcpInfo.his_ipaddr = dstipaddr; 501 break; 502 case MODE_REJ: 503 IpcpInfo.his_reject |= (1 << type); 504 break; 505 } 506 break; 507 508 /* 509 * MS extensions for MS's PPP 510 */ 511 512#ifndef NOMSEXT 513 case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */ 514 case TY_SECONDARY_DNS: 515 if (!Enabled(ConfMSExt)) { 516 LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n"); 517 IpcpInfo.my_reject |= (1 << type); 518 memcpy(rejp, cp, length); 519 rejp += length; 520 break; 521 } 522 switch (mode_type) { 523 case MODE_REQ: 524 lp = (u_long *) (cp + 2); 525 dnsstuff.s_addr = *lp; 526 ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS) ? 1 : 0)].s_addr; 527 if (dnsstuff.s_addr != ms_info_req.s_addr) { 528 529 /* 530 * So the client has got the DNS stuff wrong (first request) so 531 * we'll tell 'em how it is 532 */ 533 memcpy(nakp, cp, 2); /* copy first two (type/length) */ 534 LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n", 535 type, 536 inet_ntoa(dnsstuff), 537 inet_ntoa(ms_info_req)); 538 memcpy(nakp+2, &ms_info_req, length); 539 nakp += length; 540 break; 541 } 542 543 /* 544 * Otherwise they have it right (this time) so we send a ack packet 545 * back confirming it... end of story 546 */ 547 LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n", 548 type, 549 inet_ntoa(ms_info_req)); 550 memcpy(ackp, cp, length); 551 ackp += length; 552 break; 553 case MODE_NAK: /* what does this mean?? */ 554 LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type); 555 break; 556 case MODE_REJ: /* confused?? me to :) */ 557 LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type); 558 break; 559 } 560 break; 561 562 case TY_PRIMARY_NBNS: /* MS PPP NetBIOS nameserver hack */ 563 case TY_SECONDARY_NBNS: 564 if (!Enabled(ConfMSExt)) { 565 LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n"); 566 IpcpInfo.my_reject |= (1 << type); 567 memcpy(rejp, cp, length); 568 rejp += length; 569 break; 570 } 571 switch (mode_type) { 572 case MODE_REQ: 573 lp = (u_long *) (cp + 2); 574 dnsstuff.s_addr = *lp; 575 ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS) ? 1 : 0)].s_addr; 576 if (dnsstuff.s_addr != ms_info_req.s_addr) { 577 memcpy(nakp, cp, 2); 578 memcpy(nakp+2, &ms_info_req.s_addr, length); 579 LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n", 580 type, 581 inet_ntoa(dnsstuff), 582 inet_ntoa(ms_info_req)); 583 nakp += length; 584 break; 585 } 586 LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n", 587 type, 588 inet_ntoa(ms_info_req)); 589 memcpy(ackp, cp, length); 590 ackp += length; 591 break; 592 case MODE_NAK: 593 LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 594 break; 595 case MODE_REJ: 596 LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 597 break; 598 } 599 break; 600 601#endif 602 603 default: 604 IpcpInfo.my_reject |= (1 << type); 605 memcpy(rejp, cp, length); 606 rejp += length; 607 break; 608 } 609 plen -= length; 610 cp += length; 611 } 612} 613 614void 615IpcpInput(struct mbuf * bp) 616{ 617 FsmInput(&IpcpFsm, bp); 618} 619