xref: /freebsd/usr.sbin/ppp/ip.c (revision 2faae814fb8997c6d3c27b6e46972f4f445b19ac)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *		PPP IP Protocol Interface
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  * Redistribution and use in source and binary forms are permitted
9af57ed9fSAtsushi Murai  * provided that the above copyright notice and this paragraph are
10af57ed9fSAtsushi Murai  * duplicated in all such forms and that any documentation,
11af57ed9fSAtsushi Murai  * advertising materials, and other materials related to such
12af57ed9fSAtsushi Murai  * distribution and use acknowledge that the software was developed
13af57ed9fSAtsushi Murai  * by the Internet Initiative Japan.  The name of the
14af57ed9fSAtsushi Murai  * IIJ may not be used to endorse or promote products derived
15af57ed9fSAtsushi Murai  * from this software without specific prior written permission.
16af57ed9fSAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17af57ed9fSAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18af57ed9fSAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19af57ed9fSAtsushi Murai  *
202faae814SBrian Somers  * $Id: ip.c,v 1.65 1999/07/27 23:43:59 brian Exp $
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
23af57ed9fSAtsushi Murai  *		o Return ICMP message for filterd packet
24af57ed9fSAtsushi Murai  *		  and optionaly record it into log.
25af57ed9fSAtsushi Murai  */
26972a1bcfSBrian Somers #include <sys/param.h>
277884358fSBrian Somers #if defined(__OpenBSD__) || defined(__NetBSD__)
286a6b4bbbSBrian Somers #include <sys/socket.h>
2992b09558SBrian Somers #endif
3075240ed1SBrian Somers #include <netinet/in.h>
31af57ed9fSAtsushi Murai #include <netinet/in_systm.h>
32af57ed9fSAtsushi Murai #include <netinet/ip.h>
33af57ed9fSAtsushi Murai #include <netinet/ip_icmp.h>
34af57ed9fSAtsushi Murai #include <netinet/udp.h>
35af57ed9fSAtsushi Murai #include <netinet/tcp.h>
36ed6a16c1SPoul-Henning Kamp #include <arpa/inet.h>
371fa665f5SBrian Somers #include <sys/un.h>
3875240ed1SBrian Somers 
3957fd05c4SBrian Somers #include <errno.h>
4075240ed1SBrian Somers #include <stdio.h>
4175240ed1SBrian Somers #include <stdlib.h>
4275240ed1SBrian Somers #include <string.h>
435d9e6103SBrian Somers #include <termios.h>
4475240ed1SBrian Somers #include <unistd.h>
4575240ed1SBrian Somers 
465d9e6103SBrian Somers #include "layer.h"
475d9e6103SBrian Somers #include "proto.h"
48927145beSBrian Somers #include "mbuf.h"
49927145beSBrian Somers #include "log.h"
5075240ed1SBrian Somers #include "defs.h"
5175240ed1SBrian Somers #include "timer.h"
5275240ed1SBrian Somers #include "fsm.h"
53879ed6faSBrian Somers #include "lqr.h"
5475240ed1SBrian Somers #include "hdlc.h"
555828db6dSBrian Somers #include "throughput.h"
565828db6dSBrian Somers #include "iplist.h"
57eaa4df37SBrian Somers #include "slcompress.h"
5875240ed1SBrian Somers #include "ipcp.h"
591ae349f5Scvs2svn #include "filter.h"
602f786681SBrian Somers #include "descriptor.h"
6175240ed1SBrian Somers #include "lcp.h"
623b0f8d2eSBrian Somers #include "ccp.h"
633b0f8d2eSBrian Somers #include "link.h"
643b0f8d2eSBrian Somers #include "mp.h"
65972a1bcfSBrian Somers #ifndef NORADIUS
66972a1bcfSBrian Somers #include "radius.h"
67972a1bcfSBrian Somers #endif
687a6f8720SBrian Somers #include "bundle.h"
691ae349f5Scvs2svn #include "vjcomp.h"
706a6b4bbbSBrian Somers #include "tun.h"
7175240ed1SBrian Somers #include "ip.h"
72af57ed9fSAtsushi Murai 
73b6e82f33SBrian Somers static const u_short interactive_ports[32] = {
7476bd0c0aSDoug Rabson   544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7522d1222bSBrian Somers   80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
76af57ed9fSAtsushi Murai };
77af57ed9fSAtsushi Murai 
7876bd0c0aSDoug Rabson #define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
79af57ed9fSAtsushi Murai 
80b6e82f33SBrian Somers static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
81af57ed9fSAtsushi Murai 
82cad7e742SBrian Somers static __inline int
83944f7098SBrian Somers PortMatch(int op, u_short pport, u_short rport)
84af57ed9fSAtsushi Murai {
85af57ed9fSAtsushi Murai   switch (op) {
86af57ed9fSAtsushi Murai   case OP_EQ:
87af57ed9fSAtsushi Murai     return (pport == rport);
88af57ed9fSAtsushi Murai   case OP_GT:
89af57ed9fSAtsushi Murai     return (pport > rport);
90af57ed9fSAtsushi Murai   case OP_LT:
91af57ed9fSAtsushi Murai     return (pport < rport);
92af57ed9fSAtsushi Murai   default:
93af57ed9fSAtsushi Murai     return (0);
94af57ed9fSAtsushi Murai   }
95af57ed9fSAtsushi Murai }
96af57ed9fSAtsushi Murai 
97af57ed9fSAtsushi Murai /*
985d9e6103SBrian Somers  *  Check a packet against a defined filter
99cad7e742SBrian Somers  *  Returns 0 to accept the packet, non-zero to drop the packet
100cad7e742SBrian Somers  *
101cad7e742SBrian Somers  *  If filtering is enabled, the initial fragment of a datagram must
102cad7e742SBrian Somers  *  contain the complete protocol header, and subsequent fragments
103cad7e742SBrian Somers  *  must not attempt to over-write it.
104af57ed9fSAtsushi Murai  */
105af57ed9fSAtsushi Murai static int
106cad7e742SBrian Somers FilterCheck(const struct ip *pip, const struct filter *filter)
107af57ed9fSAtsushi Murai {
108cad7e742SBrian Somers   int gotinfo;			/* true if IP payload decoded */
109cad7e742SBrian Somers   int cproto;			/* P_* protocol type if (gotinfo) */
110cad7e742SBrian Somers   int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
111cad7e742SBrian Somers   u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
112cad7e742SBrian Somers   int n;			/* filter rule to process */
113cad7e742SBrian Somers   int len;			/* bytes used in dbuff */
114cad7e742SBrian Somers   int didname;			/* true if filter header printed */
115cad7e742SBrian Somers   int match;			/* true if condition matched */
116cad7e742SBrian Somers   const struct filterent *fp = filter->rule;
1178390b576SBrian Somers   char dbuff[100];
118af57ed9fSAtsushi Murai 
119cad7e742SBrian Somers   if (fp->f_action == A_NONE)
120cad7e742SBrian Somers     return (0);		/* No rule is given. Permit this packet */
121cad7e742SBrian Somers 
122cad7e742SBrian Somers   /* Deny any packet fragment that tries to over-write the header.
123cad7e742SBrian Somers    * Since we no longer have the real header available, punt on the
124cad7e742SBrian Somers    * largest normal header - 20 bytes for TCP without options, rounded
125cad7e742SBrian Somers    * up to the next possible fragment boundary.  Since the smallest
126cad7e742SBrian Somers    * `legal' MTU is 576, and the smallest recommended MTU is 296, any
127cad7e742SBrian Somers    * fragmentation within this range is dubious at best */
128cad7e742SBrian Somers   len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
129cad7e742SBrian Somers   if (len > 0) {		/* Not first fragment within datagram */
130cad7e742SBrian Somers     if (len < (24 >> 3))	/* don't allow fragment to over-write header */
131cad7e742SBrian Somers       return (1);
132cad7e742SBrian Somers     /* permit fragments on in and out filter */
133cad7e742SBrian Somers     return (filter->fragok);
134cad7e742SBrian Somers   }
135cad7e742SBrian Somers 
13663f98b41SBrian Somers   cproto = gotinfo = estab = syn = finrst = didname = 0;
137af57ed9fSAtsushi Murai   sport = dport = 0;
138cad7e742SBrian Somers   for (n = 0; n < MAXFILTERS; ) {
139cad7e742SBrian Somers     if (fp->f_action == A_NONE) {
140cad7e742SBrian Somers       n++;
141cad7e742SBrian Somers       fp++;
142cad7e742SBrian Somers       continue;
143cad7e742SBrian Somers     }
1445ca5389aSBrian Somers 
145cad7e742SBrian Somers     if (!didname) {
146dd7e2610SBrian Somers       log_Printf(LogDEBUG, "%s filter:\n", filter->name);
1478390b576SBrian Somers       didname = 1;
148cad7e742SBrian Somers     }
1498390b576SBrian Somers 
150cad7e742SBrian Somers     match = 0;
151cad7e742SBrian Somers     if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
152cad7e742SBrian Somers 	  fp->f_src.mask.s_addr) &&
153cad7e742SBrian Somers 	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
154cad7e742SBrian Somers 	  fp->f_dst.mask.s_addr)) {
155cad7e742SBrian Somers       if (fp->f_proto != P_NONE) {
156af57ed9fSAtsushi Murai 	if (!gotinfo) {
157cad7e742SBrian Somers 	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
158cad7e742SBrian Somers 	  const struct tcphdr *th;
159cad7e742SBrian Somers 	  const struct udphdr *uh;
160cad7e742SBrian Somers 	  const struct icmp *ih;
161cad7e742SBrian Somers 	  int datalen;	/* IP datagram length */
162af57ed9fSAtsushi Murai 
163cad7e742SBrian Somers 	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
164af57ed9fSAtsushi Murai 	  switch (pip->ip_p) {
165af57ed9fSAtsushi Murai 	  case IPPROTO_ICMP:
166944f7098SBrian Somers 	    cproto = P_ICMP;
167cad7e742SBrian Somers 	    if (datalen < 8)	/* ICMP must be at least 8 octets */
168cad7e742SBrian Somers 	      return (1);
169cad7e742SBrian Somers 	    ih = (const struct icmp *) ptop;
170944f7098SBrian Somers 	    sport = ih->icmp_type;
17163f98b41SBrian Somers 	    estab = syn = finrst = -1;
172dd7e2610SBrian Somers 	    if (log_IsKept(LogDEBUG))
1738390b576SBrian Somers 	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
174af57ed9fSAtsushi Murai 	    break;
175eee772ecSBrian Somers 	  case IPPROTO_IGMP:
1761f9e5fe5SBrian Somers 	    cproto = P_IGMP;
177cad7e742SBrian Somers 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
178cad7e742SBrian Somers 	      return (1);
1791f9e5fe5SBrian Somers 	    estab = syn = finrst = -1;
1801f9e5fe5SBrian Somers 	    sport = ntohs(0);
1811f9e5fe5SBrian Somers 	    break;
1822faae814SBrian Somers 	  case IPPROTO_OSPFIGP:
1832faae814SBrian Somers 	    cproto = P_OSPF;
1842faae814SBrian Somers 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
1852faae814SBrian Somers 	      return (1);
1862faae814SBrian Somers 	    estab = syn = finrst = -1;
1872faae814SBrian Somers 	    sport = ntohs(0);
1882faae814SBrian Somers 	    break;
1891f9e5fe5SBrian Somers 	  case IPPROTO_UDP:
190eee772ecSBrian Somers 	  case IPPROTO_IPIP:
191944f7098SBrian Somers 	    cproto = P_UDP;
192cad7e742SBrian Somers 	    if (datalen < 8)	/* UDP header is 8 octets */
193cad7e742SBrian Somers 	      return (1);
194cad7e742SBrian Somers 	    uh = (const struct udphdr *) ptop;
195944f7098SBrian Somers 	    sport = ntohs(uh->uh_sport);
196944f7098SBrian Somers 	    dport = ntohs(uh->uh_dport);
19763f98b41SBrian Somers 	    estab = syn = finrst = -1;
198dd7e2610SBrian Somers 	    if (log_IsKept(LogDEBUG))
1998390b576SBrian Somers 	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
2008390b576SBrian Somers 		       sport, dport);
201af57ed9fSAtsushi Murai 	    break;
202af57ed9fSAtsushi Murai 	  case IPPROTO_TCP:
203944f7098SBrian Somers 	    cproto = P_TCP;
204cad7e742SBrian Somers 	    th = (const struct tcphdr *) ptop;
205cad7e742SBrian Somers 	    /* TCP headers are variable length.  The following code
206cad7e742SBrian Somers 	     * ensures that the TCP header length isn't de-referenced if
207cad7e742SBrian Somers 	     * the datagram is too short
208cad7e742SBrian Somers 	     */
209cad7e742SBrian Somers 	    if (datalen < 20 || datalen < (th->th_off << 2))
210cad7e742SBrian Somers 	      return (1);
211944f7098SBrian Somers 	    sport = ntohs(th->th_sport);
212944f7098SBrian Somers 	    dport = ntohs(th->th_dport);
213af57ed9fSAtsushi Murai 	    estab = (th->th_flags & TH_ACK);
21463f98b41SBrian Somers 	    syn = (th->th_flags & TH_SYN);
21563f98b41SBrian Somers 	    finrst = (th->th_flags & (TH_FIN|TH_RST));
2162b81c773SBrian Somers 	    if (log_IsKept(LogDEBUG)) {
2172b81c773SBrian Somers 	      if (!estab)
2188390b576SBrian Somers 		snprintf(dbuff, sizeof dbuff,
2198390b576SBrian Somers 			 "flags = %02x, sport = %d, dport = %d",
220927145beSBrian Somers 			 th->th_flags, sport, dport);
2212b81c773SBrian Somers 	      else
2222b81c773SBrian Somers 		*dbuff = '\0';
2232b81c773SBrian Somers 	    }
224af57ed9fSAtsushi Murai 	    break;
225af57ed9fSAtsushi Murai 	  default:
226cad7e742SBrian Somers 	    return (1);	/* We'll block unknown type of packet */
227af57ed9fSAtsushi Murai 	  }
228cad7e742SBrian Somers 
229dd7e2610SBrian Somers 	  if (log_IsKept(LogDEBUG)) {
2308390b576SBrian Somers 	    if (estab != -1) {
2318390b576SBrian Somers 	      len = strlen(dbuff);
23263f98b41SBrian Somers 	      snprintf(dbuff + len, sizeof dbuff - len,
23363f98b41SBrian Somers 		       ", estab = %d, syn = %d, finrst = %d",
23463f98b41SBrian Somers 		       estab, syn, finrst);
235af57ed9fSAtsushi Murai 	    }
236dd7e2610SBrian Somers 	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
2378390b576SBrian Somers 		       filter_Proto2Nam(cproto), dbuff);
2388390b576SBrian Somers 	  }
2398390b576SBrian Somers 	  gotinfo = 1;
2408390b576SBrian Somers 	}
241dd7e2610SBrian Somers 	if (log_IsKept(LogDEBUG)) {
242cad7e742SBrian Somers 	  if (fp->f_srcop != OP_NONE) {
2438390b576SBrian Somers 	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
244cad7e742SBrian Somers 		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
2458390b576SBrian Somers 	    len = strlen(dbuff);
2468390b576SBrian Somers 	  } else
2478390b576SBrian Somers 	    len = 0;
248cad7e742SBrian Somers 	  if (fp->f_dstop != OP_NONE) {
2498390b576SBrian Somers 	    snprintf(dbuff + len, sizeof dbuff - len,
250cad7e742SBrian Somers 		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
251cad7e742SBrian Somers 		     fp->f_dstport);
2528390b576SBrian Somers 	  } else if (!len)
2538390b576SBrian Somers 	    *dbuff = '\0';
2548390b576SBrian Somers 
255dd7e2610SBrian Somers 	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
2568390b576SBrian Somers 		     "check against proto %s%s, action = %s\n",
257cad7e742SBrian Somers 		     n, filter_Proto2Nam(fp->f_proto),
258cad7e742SBrian Somers 		     dbuff, filter_Action2Nam(fp->f_action));
2598390b576SBrian Somers 	}
260927145beSBrian Somers 
261cad7e742SBrian Somers 	if (cproto == fp->f_proto) {
262cad7e742SBrian Somers 	  if ((fp->f_srcop == OP_NONE ||
263cad7e742SBrian Somers 	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
264cad7e742SBrian Somers 	      (fp->f_dstop == OP_NONE ||
265cad7e742SBrian Somers 	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
266cad7e742SBrian Somers 	      (fp->f_estab == 0 || estab) &&
267cad7e742SBrian Somers 	      (fp->f_syn == 0 || syn) &&
268cad7e742SBrian Somers 	      (fp->f_finrst == 0 || finrst)) {
269cad7e742SBrian Somers 	    match = 1;
270af57ed9fSAtsushi Murai 	  }
271af57ed9fSAtsushi Murai 	}
272af57ed9fSAtsushi Murai       } else {
273cad7e742SBrian Somers 	/* Address is matched and no protocol specified. Make a decision. */
274dd7e2610SBrian Somers 	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
275cad7e742SBrian Somers 		   filter_Action2Nam(fp->f_action));
276cad7e742SBrian Somers 	match = 1;
277af57ed9fSAtsushi Murai       }
2788390b576SBrian Somers     } else
279dd7e2610SBrian Somers       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
280cad7e742SBrian Somers 
281cad7e742SBrian Somers     if (match != fp->f_invert) {
282cad7e742SBrian Somers       /* Take specified action */
283cad7e742SBrian Somers       if (fp->f_action < A_NONE)
284cad7e742SBrian Somers 	fp = &filter->rule[n = fp->f_action];
285cad7e742SBrian Somers       else
286cad7e742SBrian Somers 	return (fp->f_action != A_PERMIT);
287cad7e742SBrian Somers     } else {
288cad7e742SBrian Somers       n++;
289af57ed9fSAtsushi Murai       fp++;
290af57ed9fSAtsushi Murai     }
291af57ed9fSAtsushi Murai   }
292cad7e742SBrian Somers   return (1);		/* No rule is mached. Deny this packet */
293af57ed9fSAtsushi Murai }
294af57ed9fSAtsushi Murai 
2955ca5389aSBrian Somers #ifdef notdef
296af57ed9fSAtsushi Murai static void
297944f7098SBrian Somers IcmpError(struct ip *pip, int code)
298af57ed9fSAtsushi Murai {
299af57ed9fSAtsushi Murai   struct mbuf *bp;
300af57ed9fSAtsushi Murai 
301af57ed9fSAtsushi Murai   if (pip->ip_p != IPPROTO_ICMP) {
302dd7e2610SBrian Somers     bp = mbuf_Alloc(cnt, MB_IPIN);
30375240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, cnt);
304dd7e2610SBrian Somers     vj_SendFrame(bp);
3055828db6dSBrian Somers     ipcp_AddOutOctets(cnt);
3061ae349f5Scvs2svn   }
307af57ed9fSAtsushi Murai }
308af57ed9fSAtsushi Murai #endif
309af57ed9fSAtsushi Murai 
310af57ed9fSAtsushi Murai /*
311af57ed9fSAtsushi Murai  *  For debugging aid.
312af57ed9fSAtsushi Murai  */
313af57ed9fSAtsushi Murai int
3145ca5389aSBrian Somers PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
315af57ed9fSAtsushi Murai {
316af57ed9fSAtsushi Murai   struct ip *pip;
317af57ed9fSAtsushi Murai   struct tcphdr *th;
318af57ed9fSAtsushi Murai   struct udphdr *uh;
319af57ed9fSAtsushi Murai   struct icmp *icmph;
320af57ed9fSAtsushi Murai   char *ptop;
321af57ed9fSAtsushi Murai   int mask, len, n;
322af57ed9fSAtsushi Murai   int pri = PRI_NORMAL;
32355a8cdeaSBrian Somers   int logit, loglen;
324d93d3a9cSBrian Somers   char logbuf[200];
325af57ed9fSAtsushi Murai 
326dd7e2610SBrian Somers   logit = log_IsKept(LogTCPIP) && filter->logok;
32755a8cdeaSBrian Somers   loglen = 0;
328af57ed9fSAtsushi Murai 
329af57ed9fSAtsushi Murai   pip = (struct ip *) cp;
330af57ed9fSAtsushi Murai 
33155a8cdeaSBrian Somers   if (logit && loglen < sizeof logbuf) {
3325ca5389aSBrian Somers     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
33355a8cdeaSBrian Somers     loglen += strlen(logbuf + loglen);
33455a8cdeaSBrian Somers   }
335af57ed9fSAtsushi Murai   ptop = (cp + (pip->ip_hl << 2));
336af57ed9fSAtsushi Murai 
337af57ed9fSAtsushi Murai   switch (pip->ip_p) {
338af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
33955a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
340af57ed9fSAtsushi Murai       icmph = (struct icmp *) ptop;
34155a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
34255a8cdeaSBrian Somers 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
34355a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
34455a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
34555a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
34655a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
347af57ed9fSAtsushi Murai     }
348af57ed9fSAtsushi Murai     break;
349af57ed9fSAtsushi Murai   case IPPROTO_UDP:
35055a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
351af57ed9fSAtsushi Murai       uh = (struct udphdr *) ptop;
35255a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
35355a8cdeaSBrian Somers 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
35455a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
35555a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
35655a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
35755a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
358af57ed9fSAtsushi Murai     }
359af57ed9fSAtsushi Murai     break;
3602faae814SBrian Somers   case IPPROTO_OSPFIGP:
3612faae814SBrian Somers     if (logit && loglen < sizeof logbuf) {
3622faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3632faae814SBrian Somers 	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
3642faae814SBrian Somers       loglen += strlen(logbuf + loglen);
3652faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3662faae814SBrian Somers 	       "%s", inet_ntoa(pip->ip_dst));
3672faae814SBrian Somers       loglen += strlen(logbuf + loglen);
3682faae814SBrian Somers     }
3692faae814SBrian Somers     break;
370eee772ecSBrian Somers   case IPPROTO_IPIP:
371eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
372eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
373eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
374eee772ecSBrian Somers 	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
375eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
376eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
377eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
378eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
379eee772ecSBrian Somers     }
380eee772ecSBrian Somers     break;
381eee772ecSBrian Somers   case IPPROTO_IGMP:
382eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
383eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
384eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
385eee772ecSBrian Somers 	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
386eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
387eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
388eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
389eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
390eee772ecSBrian Somers     }
391eee772ecSBrian Somers     break;
392af57ed9fSAtsushi Murai   case IPPROTO_TCP:
393af57ed9fSAtsushi Murai     th = (struct tcphdr *) ptop;
394af57ed9fSAtsushi Murai     if (pip->ip_tos == IPTOS_LOWDELAY)
395af57ed9fSAtsushi Murai       pri = PRI_FAST;
39676bd0c0aSDoug Rabson     else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
397af57ed9fSAtsushi Murai       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
398af57ed9fSAtsushi Murai 	pri = PRI_FAST;
399af57ed9fSAtsushi Murai     }
40055a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
401af57ed9fSAtsushi Murai       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
40255a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
40355a8cdeaSBrian Somers 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
40455a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
40555a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
40655a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
40755a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
408af57ed9fSAtsushi Murai       n = 0;
409af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
41055a8cdeaSBrian Somers 	if (th->th_flags & mask) {
41155a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
41255a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
41355a8cdeaSBrian Somers 	}
414af57ed9fSAtsushi Murai 	n++;
415af57ed9fSAtsushi Murai       }
41655a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
4173a2e4f62SBrian Somers 	       "  seq:%lx  ack:%lx (%d/%d)",
4183a2e4f62SBrian Somers 	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
41955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
420af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
421af57ed9fSAtsushi Murai 	u_short *sp;
422af57ed9fSAtsushi Murai 
423af57ed9fSAtsushi Murai 	ptop += 20;
424af57ed9fSAtsushi Murai 	sp = (u_short *) ptop;
42555a8cdeaSBrian Somers 	if (ntohs(sp[0]) == 0x0204) {
42655a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
42755a8cdeaSBrian Somers 		   " MSS = %d", ntohs(sp[1]));
42855a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
42955a8cdeaSBrian Somers 	}
430af57ed9fSAtsushi Murai       }
431af57ed9fSAtsushi Murai     }
432af57ed9fSAtsushi Murai     break;
433af57ed9fSAtsushi Murai   }
43476bd0c0aSDoug Rabson 
435cad7e742SBrian Somers   if (FilterCheck(pip, filter)) {
436710e9c29SBrian Somers     if (logit)
437dd7e2610SBrian Somers       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
4385ca5389aSBrian Somers #ifdef notdef
439944f7098SBrian Somers     if (direction == 0)
440944f7098SBrian Somers       IcmpError(pip, pri);
4415ca5389aSBrian Somers #endif
442af57ed9fSAtsushi Murai     return (-1);
443af57ed9fSAtsushi Murai   } else {
4445ca5389aSBrian Somers     /* Check Keep Alive filter */
445e43ebac1SBrian Somers     if (logit) {
446cad7e742SBrian Somers       if (FilterCheck(pip, &bundle->filter.alive))
447dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
4481e991daaSBrian Somers       else
449dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s\n", logbuf);
45053c9f6c0SAtsushi Murai     }
451af57ed9fSAtsushi Murai     return (pri);
452af57ed9fSAtsushi Murai   }
453af57ed9fSAtsushi Murai }
454af57ed9fSAtsushi Murai 
4555d9e6103SBrian Somers struct mbuf *
4565d9e6103SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
4577a6f8720SBrian Somers {
458af57ed9fSAtsushi Murai   int nb, nw;
459b6e82f33SBrian Somers   struct tun_data tun;
4605d9e6103SBrian Somers   struct ip *pip;
4615d9e6103SBrian Somers 
4625d9e6103SBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
4635d9e6103SBrian Somers     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
4645d9e6103SBrian Somers     mbuf_Free(bp);
4655d9e6103SBrian Somers     return NULL;
4665d9e6103SBrian Somers   }
467af57ed9fSAtsushi Murai 
468411675baSBrian Somers   mbuf_SetType(bp, MB_IPIN);
4696a6b4bbbSBrian Somers   tun_fill_header(tun, AF_INET);
4705d9e6103SBrian Somers   nb = mbuf_Length(bp);
47176d98538SBrian Somers   if (nb > sizeof tun.data) {
47276d98538SBrian Somers     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
47376d98538SBrian Somers                l->name, nb, (int)(sizeof tun.data));
47476d98538SBrian Somers     mbuf_Free(bp);
47576d98538SBrian Somers     return NULL;
47676d98538SBrian Somers   }
4775d9e6103SBrian Somers   mbuf_Read(bp, tun.data, nb);
478af57ed9fSAtsushi Murai 
4795d9e6103SBrian Somers   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
4805d9e6103SBrian Somers     return NULL;
4816db75539SBrian Somers 
4825d9e6103SBrian Somers   pip = (struct ip *)tun.data;
483cad7e742SBrian Somers   if (!FilterCheck(pip, &bundle->filter.alive))
4841e991daaSBrian Somers     bundle_StartIdleTimer(bundle);
4851e991daaSBrian Somers 
4865828db6dSBrian Somers   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
4871e991daaSBrian Somers 
48870ee81ffSBrian Somers   nb += sizeof tun - sizeof tun.data;
489faefde08SBrian Somers   nw = write(bundle->dev.fd, &tun, nb);
490c4c4aaacSBrian Somers   if (nw != nb) {
49157fd05c4SBrian Somers     if (nw == -1)
49276d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
49376d98538SBrian Somers                  l->name, nb, strerror(errno));
49457fd05c4SBrian Somers     else
49576d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
4966db75539SBrian Somers   }
4975d9e6103SBrian Somers 
4985d9e6103SBrian Somers   return NULL;
499af57ed9fSAtsushi Murai }
500af57ed9fSAtsushi Murai 
501af57ed9fSAtsushi Murai void
5025a72b6edSBrian Somers ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
503af57ed9fSAtsushi Murai {
504af57ed9fSAtsushi Murai   struct mbuf *bp;
505af57ed9fSAtsushi Murai 
5065a72b6edSBrian Somers   if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
5075a72b6edSBrian Somers     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
5085a72b6edSBrian Somers   else {
5095d9e6103SBrian Somers     /*
5105d9e6103SBrian Somers      * We allocate an extra 6 bytes, four at the front and two at the end.
5115d9e6103SBrian Somers      * This is an optimisation so that we need to do less work in
5125d9e6103SBrian Somers      * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
5135d9e6103SBrian Somers      * appending in hdlc_LayerPush().
5145d9e6103SBrian Somers      */
515411675baSBrian Somers     bp = mbuf_Alloc(count + 6, MB_IPOUT);
5165d9e6103SBrian Somers     bp->offset += 4;
5175d9e6103SBrian Somers     bp->cnt -= 6;
51875240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, count);
5195a72b6edSBrian Somers     mbuf_Enqueue(&ipcp->Queue[pri], bp);
5205a72b6edSBrian Somers   }
521af57ed9fSAtsushi Murai }
522af57ed9fSAtsushi Murai 
5236f8e9f0aSBrian Somers void
5245a72b6edSBrian Somers ip_DeleteQueue(struct ipcp *ipcp)
5256f8e9f0aSBrian Somers {
5266f8e9f0aSBrian Somers   struct mqueue *queue;
5276f8e9f0aSBrian Somers 
5285a72b6edSBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
5296f8e9f0aSBrian Somers     while (queue->top)
5306f8e9f0aSBrian Somers       mbuf_Free(mbuf_Dequeue(queue));
5316f8e9f0aSBrian Somers }
5326f8e9f0aSBrian Somers 
53384b8a6ebSAtsushi Murai int
5345a72b6edSBrian Somers ip_QueueLen(struct ipcp *ipcp)
53584b8a6ebSAtsushi Murai {
53684b8a6ebSAtsushi Murai   struct mqueue *queue;
537f4768038SBrian Somers   int result = 0;
538944f7098SBrian Somers 
5395a72b6edSBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
540f4768038SBrian Somers     result += queue->qlen;
54184b8a6ebSAtsushi Murai 
542f4768038SBrian Somers   return result;
5431ae349f5Scvs2svn }
5441ae349f5Scvs2svn 
5453b0f8d2eSBrian Somers int
5465d9e6103SBrian Somers ip_PushPacket(struct link *l, struct bundle *bundle)
547af57ed9fSAtsushi Murai {
5485a72b6edSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
549af57ed9fSAtsushi Murai   struct mqueue *queue;
550af57ed9fSAtsushi Murai   struct mbuf *bp;
5515d9e6103SBrian Somers   struct ip *pip;
552274e766cSBrian Somers   int cnt;
553af57ed9fSAtsushi Murai 
5545a72b6edSBrian Somers   if (ipcp->fsm.state != ST_OPENED)
5553b0f8d2eSBrian Somers     return 0;
5561e991daaSBrian Somers 
5575a72b6edSBrian Somers   for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
558af57ed9fSAtsushi Murai     if (queue->top) {
559aad80d9fSBrian Somers       bp = mbuf_Contiguous(mbuf_Dequeue(queue));
560dd7e2610SBrian Somers       cnt = mbuf_Length(bp);
5615d9e6103SBrian Somers       pip = (struct ip *)MBUF_CTOP(bp);
562cad7e742SBrian Somers       if (!FilterCheck(pip, &bundle->filter.alive))
563ab886ad0SBrian Somers         bundle_StartIdleTimer(bundle);
5645d9e6103SBrian Somers       link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP);
5655a72b6edSBrian Somers       ipcp_AddOutOctets(ipcp, cnt);
5663b0f8d2eSBrian Somers       return 1;
567af57ed9fSAtsushi Murai     }
5681e991daaSBrian Somers 
5693b0f8d2eSBrian Somers   return 0;
570af57ed9fSAtsushi Murai }
571