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