ip.c revision 10858
1139778Simp/*
212115Sdyson *		PPP IP Protocol Interface
312115Sdyson *
412115Sdyson *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
512115Sdyson *
612115Sdyson *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7139778Simp *
812115Sdyson * Redistribution and use in source and binary forms are permitted
912115Sdyson * provided that the above copyright notice and this paragraph are
1012115Sdyson * duplicated in all such forms and that any documentation,
1112115Sdyson * advertising materials, and other materials related to such
1212115Sdyson * distribution and use acknowledge that the software was developed
1312115Sdyson * by the Internet Initiative Japan.  The name of the
1412115Sdyson * IIJ may not be used to endorse or promote products derived
1512115Sdyson * from this software without specific prior written permission.
1612115Sdyson * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1712115Sdyson * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1812115Sdyson * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1912115Sdyson *
2012115Sdyson * $Id: ip.c,v 1.4 1995/05/30 03:50:37 rgrimes Exp $
2112115Sdyson *
2212115Sdyson *	TODO:
2312115Sdyson *		o Return ICMP message for filterd packet
2412115Sdyson *		  and optionaly record it into log.
2512115Sdyson */
2612115Sdyson#include "fsm.h"
2712115Sdyson#include "lcpproto.h"
2812115Sdyson#include "hdlc.h"
2912115Sdyson#include <netinet/in_systm.h>
3012115Sdyson#include <netinet/ip.h>
3112115Sdyson#include <netinet/ip_icmp.h>
3212115Sdyson#include <netinet/udp.h>
3312115Sdyson#include <netinet/tcp.h>
3412115Sdyson#include "vars.h"
3512115Sdyson#include "filter.h"
3612115Sdyson
3712115Sdysonextern void SendPppFrame();
3812115Sdysonextern int PacketCheck();
3912115Sdysonextern void LcpClose();
4012115Sdyson
4193016Sbdestatic struct pppTimer IdleTimer;
4212115Sdyson
4312115Sdysonstatic void IdleTimeout()
4412115Sdyson{
4512159Sbde  LogPrintf(LOG_PHASE, "Idle timer expired.\n");
4612115Sdyson  LcpClose();
4760041Sphk}
4812115Sdyson
49193377Sstas/*
5012115Sdyson *  Start Idle timer. If timeout is reached, we call LcpClose() to
5112115Sdyson *  close LCP and link.
5212115Sdyson */
5312115Sdysonvoid
5496753SiedowseStartIdleTimer()
5512115Sdyson{
5612115Sdyson  if (!(mode & MODE_DEDICATED)) {
5712115Sdyson    StopTimer(&IdleTimer);
58202283Slulf    IdleTimer.func = IdleTimeout;
59202283Slulf    IdleTimer.load = VarIdleTimeout * SECTICKS;
60202283Slulf    IdleTimer.state = TIMER_STOPPED;
61221128Sjhb    StartTimer(&IdleTimer);
62202283Slulf  }
63221128Sjhb}
6412115Sdyson
65252008Spfgvoid
6696753SiedowseStopIdleTimer()
6796753Siedowse{
6896753Siedowse  StopTimer(&IdleTimer);
6996753Siedowse}
7096753Siedowse
71141633Sphk/*
7296753Siedowse *  If any IP layer traffic is detected, refresh IdleTimer.
7396753Siedowse */
74111742Sdesstatic void
7512115SdysonRestartIdleTimer()
7612115Sdyson{
7712115Sdyson  if (!(mode & MODE_DEDICATED) && ipKeepAlive ) {
7812115Sdyson    StartTimer(&IdleTimer);
7912115Sdyson    ipIdleSecs = 0;
8012115Sdyson  }
8155477Sbde}
8255477Sbde
8355477Sbdestatic u_short interactive_ports[8] = {
8455477Sbde  0, 513, 0, 0, 0, 21, 0, 23,
8555477Sbde};
8655477Sbde
8755477Sbde#define	INTERACTIVE(p)	(interactive_ports[(p) & 7] == (p))
8855477Sbde
8955477Sbdestatic char *TcpFlags[] = {
9055477Sbde  "FIN", "SYN", "RST", "PSH", "ACK", "URG",
91247055Spfg};
92247055Spfg
9355477Sbdestatic char *Direction[] = { "INP", "OUT", "OUT", "IN/OUT" };
9455477Sbdestatic struct filterent *Filters[] = { ifilters, ofilters, dfilters, afilters };
9555477Sbde
9655477Sbdestatic int
9755477SbdePortMatch(op, pport, rport)
9855477Sbdeint op;
9955477Sbdeu_short pport, rport;
10055477Sbde{
10155477Sbde  switch (op) {
10255477Sbde  case OP_EQ:
10355477Sbde    return(pport == rport);
10455477Sbde  case OP_GT:
10555477Sbde    return(pport > rport);
10655477Sbde  case OP_LT:
10755477Sbde    return(pport < rport);
10855477Sbde  default:
10955477Sbde    return(0);
11055477Sbde  }
111247055Spfg}
112247055Spfg
11355477Sbde/*
114202283Slulf *  Check a packet against with defined filters
11593014Sbde */
116254205Spfgstatic int
117235820SpfgFilterCheck(pip, direction)
118235820Spfgstruct ip *pip;
11912159Sbdeint direction;
120254205Spfg{
121254205Spfg  struct filterent *fp = Filters[direction];
122254205Spfg  int gotinfo, cproto, estab, n;
123254205Spfg  struct tcphdr *th;
124254205Spfg  struct udphdr *uh;
125254205Spfg  struct icmp *ih;
126254205Spfg  char *ptop;
127254205Spfg  u_short sport, dport;
128254205Spfg
12912115Sdyson  if (fp->action) {
13012115Sdyson    cproto = gotinfo = estab = 0;
13112115Sdyson    sport = dport = 0;
13212115Sdyson    for (n = 0; n < MAXFILTERS; n++) {
133247209Spfg      if (fp->action) {
13412115Sdyson         /* permit fragments on in and out filter */
135254801Spfg         if ((direction == FL_IN || direction == FL_OUT) &&
136111742Sdes             (pip->ip_off & IP_OFFMASK) != 0) {
137254801Spfg              return(A_PERMIT);
138254801Spfg         }
139254801Spfg#ifdef DEBUG
140254801Spfglogprintf("rule = %d\n", n);
141254801Spfg#endif
142254801Spfg	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
143254801Spfg	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
144254801Spfg	  if (fp->proto) {
14524649Sdfr	    if (!gotinfo) {
146202283Slulf	      ptop = (char *)pip + (pip->ip_hl << 2);
147254801Spfg
14812115Sdyson	      switch (pip->ip_p) {
149254801Spfg	      case IPPROTO_ICMP:
150254801Spfg		cproto = P_ICMP; ih = (struct icmp *)ptop;
151254801Spfg		sport = ih->icmp_type; estab = 1;
152254801Spfg		break;
153254801Spfg	      case IPPROTO_UDP:
154254801Spfg		cproto = P_UDP; uh = (struct udphdr *)ptop;
155254801Spfg		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
156254801Spfg		estab = 1;
157254801Spfg		break;
158254801Spfg	      case IPPROTO_TCP:
159254801Spfg		cproto = P_TCP; th = (struct tcphdr *)ptop;
160254801Spfg		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
161254801Spfg		estab = (th->th_flags & TH_ACK);
162254801Spfg#ifdef DEBUG
163254801Spfgif (estab == 0)
16424649Sdfrlogprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
165254801Spfg#endif
166254801Spfg		break;
167254801Spfg	      default:
168254801Spfg		return(A_DENY);	/* We'll block unknown type of packet */
169254801Spfg	      }
170254801Spfg	      gotinfo = 1;
171254801Spfg#ifdef DEBUG
172254801Spfglogprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
173254801Spfgdirection, cproto, fp->opt.srcop, fp->opt.dstop, estab);
174254801Spfg#endif
175254801Spfg	    }
176254801Spfg#ifdef DEBUG
177254801Spfg	    logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
178254801Spfg		      n, cproto, sport, dport);
179254801Spfg	    logprintf("check0: action = %d\n", fp->action);
180254801Spfg#endif
181254801Spfg	    if (cproto == fp->proto) {
182254801Spfg	      if ((fp->opt.srcop == OP_NONE ||
183254801Spfg		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
184254801Spfg	       &&
185254801Spfg		  (fp->opt.dstop == OP_NONE ||
186254801Spfg		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
187254801Spfg	       &&
188254801Spfg		  (fp->opt.estab == 0 || estab)) {
189254801Spfg		return(fp->action);
190254801Spfg	      }
19155477Sbde	    }
19255477Sbde	  } else {
19355477Sbde	    /* Address is mached. Make a decision. */
19455477Sbde#ifdef DEBUG
19555477Sbde	    logprintf("check1: action = %d\n", fp->action);
196125843Sbde#endif
19755477Sbde	    return(fp->action);
19855477Sbde	  }
19955477Sbde	}
200125843Sbde      }
201125843Sbde      fp++;
20255477Sbde    }
20355477Sbdedrop:
204125843Sbde    return(A_DENY);	/* No rule is mached. Deny this packet */
20555477Sbde  }
20655477Sbde  return(A_PERMIT);	/* No rule is given. Permit this packet */
207254801Spfg}
208254801Spfg
209254801Spfgstatic void
210254801SpfgIcmpError(pip, code)
211254801Spfgstruct ip *pip;
212254801Spfgint code;
213254801Spfg{
214254801Spfg#ifdef notdef
215254801Spfg  struct mbuf *bp;
216202283Slulf
21755477Sbde  if (pip->ip_p != IPPROTO_ICMP) {
218202283Slulf    bp = mballoc(cnt, MB_IPIN);
219254801Spfg    bcopy(ptr, MBUF_CTOP(bp), cnt);
220254801Spfg    SendPppFrame(PRI_URGENT, bp);
221254801Spfg    RestartIdleTimer();
222254801Spfg    ipOutOctets += cnt;
223254801Spfg  }
224254801Spfg#endif
22512115Sdyson}
22612115Sdyson
227254801Spfg/*
228254801Spfg *  For debugging aid.
229254801Spfg */
230254801Spfgint
231254801SpfgPacketCheck(cp, nb, direction)
232254801Spfgchar *cp;
233254801Spfgint nb;
234254801Spfgint direction;
235254801Spfg{
236254801Spfg  struct ip *pip;
23724649Sdfr  struct tcphdr *th;
238254801Spfg  struct udphdr *uh;
239254801Spfg  struct icmp *icmph;
240254801Spfg  char *ptop;
241254801Spfg  int mask, len, n;
24224649Sdfr  int logit;
243254801Spfg  int pri = PRI_NORMAL;
244254801Spfg
24512115Sdyson  logit = (loglevel & (1 << LOG_TCPIP));
246254801Spfg
247254801Spfg  pip = (struct ip *)cp;
248254801Spfg
249254801Spfg  if (logit) logprintf("%s  ", Direction[direction]);
250254801Spfg
251254801Spfg  ptop = (cp + (pip->ip_hl << 2));
252254801Spfg
253254801Spfg  switch (pip->ip_p) {
254254801Spfg  case IPPROTO_ICMP:
255254801Spfg    if (logit) {
256254801Spfg      icmph = (struct icmp *)ptop;
257254801Spfg      logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
258254801Spfg      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
259254801Spfg    }
260254801Spfg    break;
261111742Sdes  case IPPROTO_UDP:
26212115Sdyson    if (logit) {
26312115Sdyson      uh = (struct udphdr *)ptop;
26412115Sdyson      logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
26512115Sdyson      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
26612115Sdyson    }
26712115Sdyson    break;
26812115Sdyson  case IPPROTO_TCP:
26912115Sdyson    th = (struct tcphdr *)ptop;
27012115Sdyson    if (pip->ip_tos == IPTOS_LOWDELAY)
27112115Sdyson      pri = PRI_FAST;
27212115Sdyson    else if (pip->ip_off == 0) {
27312115Sdyson      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
27412115Sdyson	 pri = PRI_FAST;
27512115Sdyson    }
27612115Sdyson
27712115Sdyson    if (logit) {
27812115Sdyson      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
27912115Sdyson      logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
28012115Sdyson      logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
281125843Sbde      n = 0;
28212115Sdyson      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
28312115Sdyson	if (th->th_flags & mask)
28412115Sdyson	  logprintf(" %s", TcpFlags[n]);
28512115Sdyson	n++;
28612115Sdyson      }
28712115Sdyson      logprintf("  seq:%x  ack:%x (%d/%d)\n",
28812115Sdyson	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
28912115Sdyson      if ((th->th_flags & TH_SYN) && nb > 40) {
29012115Sdyson        u_short *sp;
29112115Sdyson
29212115Sdyson	ptop += 20;
29312115Sdyson	sp = (u_short *)ptop;
29412115Sdyson	if (ntohs(sp[0]) == 0x0204)
295247209Spfg	  logprintf(" MSS = %d\n", ntohs(sp[1]));
29612115Sdyson      }
297235820Spfg    }
298235820Spfg    break;
299235820Spfg  }
300235820Spfg  pri = FilterCheck(pip, direction);
301235820Spfg  if (pri & A_DENY) {
302235820Spfg#ifdef DEBUG
303235820Spfg    logprintf("blocked.\n");
304235820Spfg#endif
30596752Siedowse    if (direction == 0) IcmpError(pip, pri);
30612115Sdyson    return(-1);
307202283Slulf  } else {
30812115Sdyson    if ( FilterCheck(pip, FL_KEEP ) & A_DENY ) {  /* Check Keep Alive filter */
309254205Spfg	ipKeepAlive = FALSE;
310202283Slulf    } else {
311202283Slulf	ipKeepAlive = TRUE;
31212115Sdyson    }
31312115Sdyson    return(pri);
31412115Sdyson  }
31512115Sdyson}
31612115Sdyson
31712115Sdysonvoid
31812115SdysonIpInput(bp)
319254205Spfgstruct mbuf *bp;		/* IN: Pointer to IP pakcet */
32012115Sdyson{
32112115Sdyson  u_char *cp;
32212115Sdyson  struct mbuf *wp;
323235820Spfg  int nb, nw;
324202283Slulf  u_char tunbuff[MAX_MRU];
325254205Spfg
32612115Sdyson  cp = tunbuff;
327235820Spfg  nb = 0;
32812115Sdyson  for (wp = bp; wp; wp = wp->next) {		/* Copy to continuois region */
329235820Spfg    bcopy(MBUF_CTOP(wp), cp, wp->cnt);
330235820Spfg    cp += wp->cnt;
331235820Spfg    nb += wp->cnt;
332235820Spfg  }
333235820Spfg
334235820Spfg  if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) {
33512115Sdyson    pfree(bp);
336254205Spfg    return;
337217584Sjhb  }
33812115Sdyson
33912115Sdyson  ipInOctets += nb;
340254205Spfg  /*
34112115Sdyson   *  Pass it to tunnel device
34212115Sdyson   */
34312115Sdyson  nw = write(tun_out, tunbuff, nb);
34412115Sdyson  if (nw != nb)
34512115Sdyson    fprintf(stderr, "wrote %d, got %d\r\n");
346202283Slulf  pfree(bp);
347202283Slulf
348254205Spfg  RestartIdleTimer();
349254205Spfg}
35012115Sdyson
35112115Sdysonvoid
352254205SpfgIpOutput(ptr, cnt)
353254205Spfgu_char *ptr;			/* IN: Pointer to IP packet */
35412115Sdysonint cnt;			/* IN: Length of packet */
355254205Spfg{
35612115Sdyson  struct mbuf *bp;
35712115Sdyson  int pri;
35812115Sdyson
35912115Sdyson  if (IpcpFsm.state != ST_OPENED)
360254205Spfg    return;
361254205Spfg
362254205Spfg  pri = PacketCheck(ptr, cnt, FL_OUT);
363254205Spfg  if (pri >= 0) {
364254205Spfg    bp = mballoc(cnt, MB_IPIN);
365254205Spfg    bcopy(ptr, MBUF_CTOP(bp), cnt);
366254205Spfg    SendPppFrame(pri, bp);
367254205Spfg    RestartIdleTimer();
368254205Spfg    ipOutOctets += cnt;
369254205Spfg  }
370254205Spfg}
371254205Spfg
372254205Spfgstatic struct mqueue IpOutputQueues[PRI_URGENT+1];
373254205Spfg
374254205Spfgvoid
375254205SpfgIpEnqueue(pri, ptr, count)
376254205Spfgint pri;
377254205Spfgchar *ptr;
378254205Spfgint count;
379254205Spfg{
380254205Spfg  struct mbuf *bp;
381254205Spfg
382254205Spfg  bp = mballoc(count, MB_IPQ);
383254205Spfg  bcopy(ptr, MBUF_CTOP(bp), count);
384254205Spfg  Enqueue(&IpOutputQueues[pri], bp);
385254205Spfg}
386254205Spfg
387254205Spfgint
38812115SdysonIsIpEnqueued()
38912115Sdyson{
39012115Sdyson  struct mqueue *queue;
39112115Sdyson  int    exist = FALSE;
39212115Sdyson  for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
39312115Sdyson     if ( queue->qlen > 0 ) {
39412115Sdyson       exist = TRUE;
39512115Sdyson       break;
39612115Sdyson     }
39712115Sdyson  }
398202283Slulf  return( exist );
399202283Slulf}
40012115Sdyson
401202283Slulfvoid
40212115SdysonIpStartOutput()
40312115Sdyson{
404202283Slulf  struct mqueue *queue;
405202283Slulf  struct mbuf *bp;
406202283Slulf  int pri, cnt;
40796749Siedowse
40812115Sdyson  if (IpcpFsm.state != ST_OPENED)
40912115Sdyson    return;
41012115Sdyson  pri = PRI_URGENT;
41112115Sdyson  for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
412202283Slulf    if (queue->top) {
413202283Slulf      bp = Dequeue(queue);
41412115Sdyson      if (bp) {
41512115Sdyson	cnt = plength(bp);
41612115Sdyson	SendPppFrame(pri, bp);
417202283Slulf	RestartIdleTimer();
41812115Sdyson	ipOutOctets += cnt;
41912115Sdyson       }
42012115Sdyson    }
421254205Spfg    pri--;
422254205Spfg  }
423254205Spfg}
424254205Spfg