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