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