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