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