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