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