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