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