xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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