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