ip.c revision 32247
1/*
2 *		PPP IP Protocol Interface
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.  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: ip.c,v 1.35 1997/12/29 22:23:11 brian Exp $
21 *
22 *	TODO:
23 *		o Return ICMP message for filterd packet
24 *		  and optionaly record it into log.
25 */
26#include <sys/param.h>
27#include <sys/time.h>
28#include <sys/select.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <netinet/in_systm.h>
32#include <netinet/ip.h>
33#include <netinet/ip_icmp.h>
34#include <netinet/udp.h>
35#include <netinet/tcp.h>
36#include <arpa/inet.h>
37#include <net/if.h>
38#ifdef __FreeBSD__
39#include <net/if_var.h>
40#endif
41#include <net/if_tun.h>
42
43#ifndef NOALIAS
44#include <alias.h>
45#endif
46#include <errno.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <termios.h>
51#include <unistd.h>
52
53#include "command.h"
54#include "mbuf.h"
55#include "log.h"
56#include "defs.h"
57#include "timer.h"
58#include "fsm.h"
59#include "lcpproto.h"
60#include "hdlc.h"
61#include "loadalias.h"
62#include "vars.h"
63#include "filter.h"
64#include "os.h"
65#include "ipcp.h"
66#include "vjcomp.h"
67#include "lcp.h"
68#include "modem.h"
69#include "tun.h"
70#include "ip.h"
71
72static struct pppTimer IdleTimer;
73
74static void
75IdleTimeout(void *v)
76{
77  LogPrintf(LogPHASE, "Idle timer expired.\n");
78  reconnect(RECON_FALSE);
79  LcpClose();
80}
81
82/*
83 *  Start Idle timer. If timeout is reached, we call LcpClose() to
84 *  close LCP and link.
85 */
86void
87StartIdleTimer()
88{
89  static time_t IdleStarted;
90
91  if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
92    StopTimer(&IdleTimer);
93    IdleTimer.func = IdleTimeout;
94    IdleTimer.load = VarIdleTimeout * SECTICKS;
95    IdleTimer.state = TIMER_STOPPED;
96    time(&IdleStarted);
97    IdleTimer.arg = (void *)&IdleStarted;
98    StartTimer(&IdleTimer);
99  }
100}
101
102void
103UpdateIdleTimer()
104{
105  if (OsLinkIsUp())
106    StartIdleTimer();
107}
108
109void
110StopIdleTimer()
111{
112  StopTimer(&IdleTimer);
113}
114
115int
116RemainingIdleTime()
117{
118  if (VarIdleTimeout == 0 || IdleTimer.state != TIMER_RUNNING ||
119      IdleTimer.arg == NULL)
120    return -1;
121  return VarIdleTimeout - (time(NULL) - *(time_t *)IdleTimer.arg);
122}
123
124/*
125 *  If any IP layer traffic is detected, refresh IdleTimer.
126 */
127static void
128RestartIdleTimer(void)
129{
130  if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
131    time((time_t *)IdleTimer.arg);
132    StartTimer(&IdleTimer);
133  }
134}
135
136static const u_short interactive_ports[32] = {
137  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
139};
140
141#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
142
143static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
144
145static const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
146static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
147
148static int
149PortMatch(int op, u_short pport, u_short rport)
150{
151  switch (op) {
152    case OP_EQ:
153    return (pport == rport);
154  case OP_GT:
155    return (pport > rport);
156  case OP_LT:
157    return (pport < rport);
158  default:
159    return (0);
160  }
161}
162
163/*
164 *  Check a packet against with defined filters
165 */
166static int
167FilterCheck(struct ip * pip, int direction)
168{
169  struct filterent *fp = Filters[direction];
170  int gotinfo, cproto, estab, n;
171  struct tcphdr *th;
172  struct udphdr *uh;
173  struct icmp *ih;
174  char *ptop;
175  u_short sport, dport;
176
177  if (fp->action) {
178    cproto = gotinfo = estab = 0;
179    sport = dport = 0;
180    for (n = 0; n < MAXFILTERS; n++) {
181      if (fp->action) {
182	/* permit fragments on in and out filter */
183	if ((direction == FL_IN || direction == FL_OUT) &&
184	    (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
185	  return (A_PERMIT);
186	}
187	LogPrintf(LogDEBUG, "rule = %d\n", n);
188	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
189	    (fp->saddr.s_addr & fp->smask.s_addr) &&
190	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
191	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
192	  if (fp->proto) {
193	    if (!gotinfo) {
194	      ptop = (char *) pip + (pip->ip_hl << 2);
195
196	      switch (pip->ip_p) {
197	      case IPPROTO_ICMP:
198		cproto = P_ICMP;
199		ih = (struct icmp *) ptop;
200		sport = ih->icmp_type;
201		estab = 1;
202		break;
203	      case IPPROTO_UDP:
204		cproto = P_UDP;
205		uh = (struct udphdr *) ptop;
206		sport = ntohs(uh->uh_sport);
207		dport = ntohs(uh->uh_dport);
208		estab = 1;
209		break;
210	      case IPPROTO_TCP:
211		cproto = P_TCP;
212		th = (struct tcphdr *) ptop;
213		sport = ntohs(th->th_sport);
214		dport = ntohs(th->th_dport);
215		estab = (th->th_flags & TH_ACK);
216		if (estab == 0)
217		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
218			    th->th_flags, sport, dport);
219		break;
220	      default:
221		return (A_DENY);/* We'll block unknown type of packet */
222	      }
223	      gotinfo = 1;
224	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
225			" dstop = %d, estab = %d\n", direction, cproto,
226			fp->opt.srcop, fp->opt.dstop, estab);
227	    }
228	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
229		      " dport = %d\n", n, cproto, sport, dport);
230	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
231
232	    if (cproto == fp->proto) {
233	      if ((fp->opt.srcop == OP_NONE ||
234		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
235		  &&
236		  (fp->opt.dstop == OP_NONE ||
237		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
238		  &&
239		  (fp->opt.estab == 0 || estab)) {
240		return (fp->action);
241	      }
242	    }
243	  } else {
244	    /* Address is mached. Make a decision. */
245	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
246	    return (fp->action);
247	  }
248	}
249      }
250      fp++;
251    }
252    return (A_DENY);		/* No rule is mached. Deny this packet */
253  }
254  return (A_PERMIT);		/* No rule is given. Permit this packet */
255}
256
257static void
258IcmpError(struct ip * pip, int code)
259{
260#ifdef notdef
261  struct mbuf *bp;
262
263  if (pip->ip_p != IPPROTO_ICMP) {
264    bp = mballoc(cnt, MB_IPIN);
265    memcpy(MBUF_CTOP(bp), ptr, cnt);
266    SendPppFrame(bp);
267    RestartIdleTimer();
268    IpcpAddOutOctets(cnt);
269  }
270#endif
271}
272
273/*
274 *  For debugging aid.
275 */
276int
277PacketCheck(char *cp, int nb, int direction)
278{
279  struct ip *pip;
280  struct tcphdr *th;
281  struct udphdr *uh;
282  struct icmp *icmph;
283  char *ptop;
284  int mask, len, n;
285  int pri = PRI_NORMAL;
286  int logit, loglen;
287  static char logbuf[200];
288
289  logit = LogIsKept(LogTCPIP) && direction != FL_DIAL;
290  loglen = 0;
291
292  pip = (struct ip *) cp;
293
294  if (logit && loglen < sizeof logbuf) {
295    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
296	     Direction[direction]);
297    loglen += strlen(logbuf + loglen);
298  }
299  ptop = (cp + (pip->ip_hl << 2));
300
301  switch (pip->ip_p) {
302  case IPPROTO_ICMP:
303    if (logit && loglen < sizeof logbuf) {
304      icmph = (struct icmp *) ptop;
305      snprintf(logbuf + loglen, sizeof logbuf - loglen,
306	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
307      loglen += strlen(logbuf + loglen);
308      snprintf(logbuf + loglen, sizeof logbuf - loglen,
309	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
310      loglen += strlen(logbuf + loglen);
311    }
312    break;
313  case IPPROTO_UDP:
314    if (logit && loglen < sizeof logbuf) {
315      uh = (struct udphdr *) ptop;
316      snprintf(logbuf + loglen, sizeof logbuf - loglen,
317	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
318      loglen += strlen(logbuf + loglen);
319      snprintf(logbuf + loglen, sizeof logbuf - loglen,
320	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
321      loglen += strlen(logbuf + loglen);
322    }
323    break;
324  case IPPROTO_TCP:
325    th = (struct tcphdr *) ptop;
326    if (pip->ip_tos == IPTOS_LOWDELAY)
327      pri = PRI_FAST;
328    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
329      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
330	pri = PRI_FAST;
331    }
332    if (logit && loglen < sizeof logbuf) {
333      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
334      snprintf(logbuf + loglen, sizeof logbuf - loglen,
335	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
336      loglen += strlen(logbuf + loglen);
337      snprintf(logbuf + loglen, sizeof logbuf - loglen,
338	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
339      loglen += strlen(logbuf + loglen);
340      n = 0;
341      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
342	if (th->th_flags & mask) {
343	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
344	  loglen += strlen(logbuf + loglen);
345	}
346	n++;
347      }
348      snprintf(logbuf + loglen, sizeof logbuf - loglen,
349	       "  seq:%x  ack:%x (%d/%d)",
350	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
351      loglen += strlen(logbuf + loglen);
352      if ((th->th_flags & TH_SYN) && nb > 40) {
353	u_short *sp;
354
355	ptop += 20;
356	sp = (u_short *) ptop;
357	if (ntohs(sp[0]) == 0x0204) {
358	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
359		   " MSS = %d", ntohs(sp[1]));
360	  loglen += strlen(logbuf + loglen);
361	}
362      }
363    }
364    break;
365  }
366
367  if ((FilterCheck(pip, direction) & A_DENY)) {
368    if (logit)
369      LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
370    if (direction == 0)
371      IcmpError(pip, pri);
372    return (-1);
373  } else {
374    if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
375      if (logit)
376        LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
377      ipKeepAlive = 0;
378    } else {
379      if (logit)
380        LogPrintf(LogTCPIP, "%s\n", logbuf);
381      ipKeepAlive = 1;
382    }
383    return (pri);
384  }
385}
386
387void
388IpInput(struct mbuf * bp)
389{				/* IN: Pointer to IP pakcet */
390  u_char *cp;
391  struct mbuf *wp;
392  int nb, nw;
393  struct tun_data tun;
394
395  tun_fill_header(tun, AF_INET);
396  cp = tun.data;
397  nb = 0;
398  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
399    if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
400      LogPrintf(LogERROR, "IpInput: Packet too large (%d) - dropped\n",
401                plength(bp));
402      pfree(bp);
403      return;
404    }
405    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
406    cp += wp->cnt;
407    nb += wp->cnt;
408  }
409
410#ifndef NOALIAS
411  if (mode & MODE_ALIAS) {
412    struct tun_data *frag;
413    int iresult;
414    char *fptr;
415
416    iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
417    nb = ntohs(((struct ip *) tun.data)->ip_len);
418
419    if (nb > MAX_MRU) {
420      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
421      pfree(bp);
422      return;
423    }
424    if (iresult == PKT_ALIAS_OK
425	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
426      if (PacketCheck(tun.data, nb, FL_IN) < 0) {
427	pfree(bp);
428	return;
429      }
430      IpcpAddInOctets(nb);
431
432      nb = ntohs(((struct ip *) tun.data)->ip_len);
433      nb += sizeof tun - sizeof tun.data;
434      nw = write(tun_out, &tun, nb);
435      if (nw != nb)
436        if (nw == -1)
437	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
438                    strerror(errno));
439        else
440	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
441
442      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
443	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
444	  VarPacketAliasFragmentIn(tun.data, fptr);
445	  nb = ntohs(((struct ip *) fptr)->ip_len);
446          frag = (struct tun_data *)
447	    ((char *)fptr - sizeof tun + sizeof tun.data);
448          nb += sizeof tun - sizeof tun.data;
449	  nw = write(tun_out, frag, nb);
450	  if (nw != nb)
451            if (nw == -1)
452	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
453                        strerror(errno));
454            else
455	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
456	  free(frag);
457	}
458      }
459    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
460      nb = ntohs(((struct ip *) tun.data)->ip_len);
461      nb += sizeof tun - sizeof tun.data;
462      frag = (struct tun_data *)malloc(nb);
463      if (frag == NULL)
464	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
465      else {
466        tun_fill_header(*frag, AF_INET);
467	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
468	VarPacketAliasSaveFragment(frag->data);
469      }
470    }
471  } else
472#endif /* #ifndef NOALIAS */
473  {			/* no aliasing */
474    if (PacketCheck(tun.data, nb, FL_IN) < 0) {
475      pfree(bp);
476      return;
477    }
478    IpcpAddInOctets(nb);
479    nb += sizeof tun - sizeof tun.data;
480    nw = write(tun_out, &tun, nb);
481    if (nw != nb)
482      if (nw == -1)
483	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
484      else
485        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
486  }
487  pfree(bp);
488
489  RestartIdleTimer();
490}
491
492static struct mqueue IpOutputQueues[PRI_FAST + 1];
493
494void
495IpEnqueue(int pri, char *ptr, int count)
496{
497  struct mbuf *bp;
498
499  bp = mballoc(count, MB_IPQ);
500  memcpy(MBUF_CTOP(bp), ptr, count);
501  Enqueue(&IpOutputQueues[pri], bp);
502}
503
504#if 0
505int
506IsIpEnqueued()
507{
508  struct mqueue *queue;
509  int exist = 0;
510
511  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
512    if (queue->qlen > 0) {
513      exist = 1;
514      break;
515    }
516  }
517  return (exist);
518}
519#endif
520
521void
522IpStartOutput()
523{
524  struct mqueue *queue;
525  struct mbuf *bp;
526  int cnt;
527
528  if (IpcpFsm.state != ST_OPENED)
529    return;
530  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
531    if (queue->top) {
532      bp = Dequeue(queue);
533      if (bp) {
534	cnt = plength(bp);
535	SendPppFrame(bp);
536	RestartIdleTimer();
537        IpcpAddOutOctets(cnt);
538	break;
539      }
540    }
541  }
542}
543