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