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