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