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