ip.c revision 26516
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.20 1997/05/26 00:44:01 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 logit;
249  int pri = PRI_NORMAL;
250
251  logit = LogIsKept(LogTCPIP);
252
253  pip = (struct ip *)cp;
254
255  if (logit) LogPrintf(LogTCPIP, "%s  ", Direction[direction]);
256
257  ptop = (cp + (pip->ip_hl << 2));
258
259  switch (pip->ip_p) {
260  case IPPROTO_ICMP:
261    if (logit) {
262      icmph = (struct icmp *)ptop;
263      LogPrintf(LogTCPIP, "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
264      LogPrintf(LogTCPIP, "%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
265    }
266    break;
267  case IPPROTO_UDP:
268    if (logit) {
269      uh = (struct udphdr *)ptop;
270      LogPrintf(LogTCPIP, "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
271      LogPrintf(LogTCPIP, "%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
272    }
273    break;
274  case IPPROTO_TCP:
275    th = (struct tcphdr *)ptop;
276    if (pip->ip_tos == IPTOS_LOWDELAY)
277      pri = PRI_FAST;
278    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
279      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
280	 pri = PRI_FAST;
281    }
282
283    if (logit) {
284      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
285      LogPrintf(LogTCPIP, "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
286      LogPrintf(LogTCPIP, "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
287      n = 0;
288      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
289	if (th->th_flags & mask)
290	  LogPrintf(LogTCPIP, " %s", TcpFlags[n]);
291	n++;
292      }
293      LogPrintf(LogTCPIP, "  seq:%x  ack:%x (%d/%d)\n",
294	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
295      if ((th->th_flags & TH_SYN) && nb > 40) {
296        u_short *sp;
297
298	ptop += 20;
299	sp = (u_short *)ptop;
300	if (ntohs(sp[0]) == 0x0204)
301	  LogPrintf(LogTCPIP, " MSS = %d\n", ntohs(sp[1]));
302      }
303    }
304    break;
305  }
306
307  if ((FilterCheck(pip, direction) & A_DENY)) {
308    LogPrintf(LogDEBUG, "blocked.\n");
309    if (direction == 0) IcmpError(pip, pri);
310    return(-1);
311  } else {
312    if ( FilterCheck(pip, FL_KEEP ) & A_DENY ) {  /* Check Keep Alive filter */
313	ipKeepAlive = FALSE;
314    } else {
315	ipKeepAlive = TRUE;
316    }
317    return(pri);
318  }
319}
320
321void
322IpInput(bp)
323struct mbuf *bp;		/* IN: Pointer to IP pakcet */
324{
325  u_char *cp;
326  struct mbuf *wp;
327  int nb, nw;
328  u_char tunbuff[MAX_MRU];
329
330  cp = tunbuff;
331  nb = 0;
332  for (wp = bp; wp; wp = wp->next) {		/* Copy to contiguous region */
333    bcopy(MBUF_CTOP(wp), cp, wp->cnt);
334    cp += wp->cnt;
335    nb += wp->cnt;
336  }
337
338  if (mode & MODE_ALIAS) {
339    int iresult;
340    char *fptr;
341
342    iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff);
343    nb = ntohs(((struct ip *) tunbuff)->ip_len);
344
345    if (nb > MAX_MRU) {
346      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
347      pfree(bp);
348      return;
349    }
350
351    if (iresult == PKT_ALIAS_OK
352     || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
353      if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) {
354          pfree(bp);
355          return;
356      }
357
358      ipInOctets += nb;
359
360      nb = ntohs(((struct ip *) tunbuff)->ip_len);
361      nw = write(tun_out, tunbuff, nb);
362      if (nw != nb)
363        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
364
365      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
366        while ((fptr = VarGetNextFragmentPtr(tunbuff)) != NULL) {
367          VarFragmentAliasIn(tunbuff, fptr);
368          nb = ntohs(((struct ip *) fptr)->ip_len);
369          nw = write(tun_out, fptr, nb);
370          if (nw != nb)
371            LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
372          free(fptr);
373        }
374      }
375    }
376    else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
377      nb = ntohs(((struct ip *) tunbuff)->ip_len);
378      fptr = malloc(nb);
379      if (fptr == NULL)
380        LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
381      else {
382        memcpy(fptr, tunbuff, nb);
383        VarSaveFragmentPtr(fptr);
384      }
385    }
386  }
387  else
388  { /* no aliasing */
389    if ( PacketCheck(tunbuff, nb, FL_IN ) < 0)
390    {
391      pfree(bp);
392      return;
393    }
394
395    ipInOctets += nb;
396    nw = write(tun_out, tunbuff, nb);
397    if (nw != nb)
398      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
399  }
400  pfree(bp);
401
402  RestartIdleTimer();
403}
404
405static struct mqueue IpOutputQueues[PRI_FAST+1];
406
407void
408IpEnqueue(pri, ptr, count)
409int pri;
410char *ptr;
411int count;
412{
413  struct mbuf *bp;
414
415  bp = mballoc(count, MB_IPQ);
416  bcopy(ptr, MBUF_CTOP(bp), count);
417  Enqueue(&IpOutputQueues[pri], bp);
418}
419
420int
421IsIpEnqueued()
422{
423  struct mqueue *queue;
424  int    exist = FALSE;
425  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
426     if ( queue->qlen > 0 ) {
427       exist = TRUE;
428       break;
429     }
430  }
431  return( exist );
432}
433
434void
435IpStartOutput()
436{
437  struct mqueue *queue;
438  struct mbuf *bp;
439  int cnt;
440
441  if (IpcpFsm.state != ST_OPENED)
442    return;
443  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
444    if (queue->top) {
445      bp = Dequeue(queue);
446      if (bp) {
447	cnt = plength(bp);
448	SendPppFrame(bp);
449	RestartIdleTimer();
450	ipOutOctets += cnt;
451	break;
452       }
453    }
454  }
455}
456