xref: /freebsd/usr.sbin/ppp/ip.c (revision da477886496304969384fd67cc1d630ab5f76f34)
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  *
2097d92980SPeter Wemm  * $FreeBSD$
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 <string.h>
425d9e6103SBrian Somers #include <termios.h>
4375240ed1SBrian Somers #include <unistd.h>
4475240ed1SBrian Somers 
455d9e6103SBrian Somers #include "layer.h"
465d9e6103SBrian Somers #include "proto.h"
47927145beSBrian Somers #include "mbuf.h"
48927145beSBrian Somers #include "log.h"
4975240ed1SBrian Somers #include "defs.h"
5075240ed1SBrian Somers #include "timer.h"
5175240ed1SBrian Somers #include "fsm.h"
52879ed6faSBrian Somers #include "lqr.h"
5375240ed1SBrian Somers #include "hdlc.h"
545828db6dSBrian Somers #include "throughput.h"
555828db6dSBrian Somers #include "iplist.h"
56eaa4df37SBrian Somers #include "slcompress.h"
5775240ed1SBrian Somers #include "ipcp.h"
581ae349f5Scvs2svn #include "filter.h"
592f786681SBrian Somers #include "descriptor.h"
6075240ed1SBrian Somers #include "lcp.h"
613b0f8d2eSBrian Somers #include "ccp.h"
623b0f8d2eSBrian Somers #include "link.h"
633b0f8d2eSBrian Somers #include "mp.h"
64972a1bcfSBrian Somers #ifndef NORADIUS
65972a1bcfSBrian Somers #include "radius.h"
66972a1bcfSBrian Somers #endif
677a6f8720SBrian Somers #include "bundle.h"
686a6b4bbbSBrian Somers #include "tun.h"
6975240ed1SBrian Somers #include "ip.h"
70af57ed9fSAtsushi Murai 
71b6e82f33SBrian Somers static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
72af57ed9fSAtsushi Murai 
73cad7e742SBrian Somers static __inline int
74944f7098SBrian Somers PortMatch(int op, u_short pport, u_short rport)
75af57ed9fSAtsushi Murai {
76af57ed9fSAtsushi Murai   switch (op) {
77af57ed9fSAtsushi Murai   case OP_EQ:
78af57ed9fSAtsushi Murai     return (pport == rport);
79af57ed9fSAtsushi Murai   case OP_GT:
80af57ed9fSAtsushi Murai     return (pport > rport);
81af57ed9fSAtsushi Murai   case OP_LT:
82af57ed9fSAtsushi Murai     return (pport < rport);
83af57ed9fSAtsushi Murai   default:
84af57ed9fSAtsushi Murai     return (0);
85af57ed9fSAtsushi Murai   }
86af57ed9fSAtsushi Murai }
87af57ed9fSAtsushi Murai 
88af57ed9fSAtsushi Murai /*
895d9e6103SBrian Somers  *  Check a packet against a defined filter
90cad7e742SBrian Somers  *  Returns 0 to accept the packet, non-zero to drop the packet
91cad7e742SBrian Somers  *
92cad7e742SBrian Somers  *  If filtering is enabled, the initial fragment of a datagram must
93cad7e742SBrian Somers  *  contain the complete protocol header, and subsequent fragments
94cad7e742SBrian Somers  *  must not attempt to over-write it.
95af57ed9fSAtsushi Murai  */
96af57ed9fSAtsushi Murai static int
97cad7e742SBrian Somers FilterCheck(const struct ip *pip, const struct filter *filter)
98af57ed9fSAtsushi Murai {
99cad7e742SBrian Somers   int gotinfo;			/* true if IP payload decoded */
100cad7e742SBrian Somers   int cproto;			/* P_* protocol type if (gotinfo) */
101cad7e742SBrian Somers   int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
102cad7e742SBrian Somers   u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
103cad7e742SBrian Somers   int n;			/* filter rule to process */
104cad7e742SBrian Somers   int len;			/* bytes used in dbuff */
105cad7e742SBrian Somers   int didname;			/* true if filter header printed */
106cad7e742SBrian Somers   int match;			/* true if condition matched */
107cad7e742SBrian Somers   const struct filterent *fp = filter->rule;
1088390b576SBrian Somers   char dbuff[100];
109af57ed9fSAtsushi Murai 
110cad7e742SBrian Somers   if (fp->f_action == A_NONE)
111cad7e742SBrian Somers     return (0);		/* No rule is given. Permit this packet */
112cad7e742SBrian Somers 
113cad7e742SBrian Somers   /* Deny any packet fragment that tries to over-write the header.
114cad7e742SBrian Somers    * Since we no longer have the real header available, punt on the
115cad7e742SBrian Somers    * largest normal header - 20 bytes for TCP without options, rounded
116cad7e742SBrian Somers    * up to the next possible fragment boundary.  Since the smallest
117cad7e742SBrian Somers    * `legal' MTU is 576, and the smallest recommended MTU is 296, any
118cad7e742SBrian Somers    * fragmentation within this range is dubious at best */
119cad7e742SBrian Somers   len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
120cad7e742SBrian Somers   if (len > 0) {		/* Not first fragment within datagram */
121cad7e742SBrian Somers     if (len < (24 >> 3))	/* don't allow fragment to over-write header */
122cad7e742SBrian Somers       return (1);
123cad7e742SBrian Somers     /* permit fragments on in and out filter */
124cad7e742SBrian Somers     return (filter->fragok);
125cad7e742SBrian Somers   }
126cad7e742SBrian Somers 
12763f98b41SBrian Somers   cproto = gotinfo = estab = syn = finrst = didname = 0;
128af57ed9fSAtsushi Murai   sport = dport = 0;
129cad7e742SBrian Somers   for (n = 0; n < MAXFILTERS; ) {
130cad7e742SBrian Somers     if (fp->f_action == A_NONE) {
131cad7e742SBrian Somers       n++;
132cad7e742SBrian Somers       fp++;
133cad7e742SBrian Somers       continue;
134cad7e742SBrian Somers     }
1355ca5389aSBrian Somers 
136cad7e742SBrian Somers     if (!didname) {
137dd7e2610SBrian Somers       log_Printf(LogDEBUG, "%s filter:\n", filter->name);
1388390b576SBrian Somers       didname = 1;
139cad7e742SBrian Somers     }
1408390b576SBrian Somers 
141cad7e742SBrian Somers     match = 0;
142cad7e742SBrian Somers     if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
143cad7e742SBrian Somers 	  fp->f_src.mask.s_addr) &&
144cad7e742SBrian Somers 	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
145cad7e742SBrian Somers 	  fp->f_dst.mask.s_addr)) {
146cad7e742SBrian Somers       if (fp->f_proto != P_NONE) {
147af57ed9fSAtsushi Murai 	if (!gotinfo) {
148cad7e742SBrian Somers 	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
149cad7e742SBrian Somers 	  const struct tcphdr *th;
150cad7e742SBrian Somers 	  const struct udphdr *uh;
151cad7e742SBrian Somers 	  const struct icmp *ih;
152cad7e742SBrian Somers 	  int datalen;	/* IP datagram length */
153af57ed9fSAtsushi Murai 
154cad7e742SBrian Somers 	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
155af57ed9fSAtsushi Murai 	  switch (pip->ip_p) {
156af57ed9fSAtsushi Murai 	  case IPPROTO_ICMP:
157944f7098SBrian Somers 	    cproto = P_ICMP;
158cad7e742SBrian Somers 	    if (datalen < 8)	/* ICMP must be at least 8 octets */
159cad7e742SBrian Somers 	      return (1);
160cad7e742SBrian Somers 	    ih = (const struct icmp *) ptop;
161944f7098SBrian Somers 	    sport = ih->icmp_type;
16263f98b41SBrian Somers 	    estab = syn = finrst = -1;
163dd7e2610SBrian Somers 	    if (log_IsKept(LogDEBUG))
1648390b576SBrian Somers 	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
165af57ed9fSAtsushi Murai 	    break;
166eee772ecSBrian Somers 	  case IPPROTO_IGMP:
1671f9e5fe5SBrian Somers 	    cproto = P_IGMP;
168cad7e742SBrian Somers 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
169cad7e742SBrian Somers 	      return (1);
1701f9e5fe5SBrian Somers 	    estab = syn = finrst = -1;
1711f9e5fe5SBrian Somers 	    sport = ntohs(0);
1721f9e5fe5SBrian Somers 	    break;
17362e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
1742faae814SBrian Somers 	  case IPPROTO_OSPFIGP:
1752faae814SBrian Somers 	    cproto = P_OSPF;
1762faae814SBrian Somers 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
1772faae814SBrian Somers 	      return (1);
1782faae814SBrian Somers 	    estab = syn = finrst = -1;
1792faae814SBrian Somers 	    sport = ntohs(0);
1802faae814SBrian Somers 	    break;
18162e85934SBrian Somers #endif
1821f9e5fe5SBrian Somers 	  case IPPROTO_UDP:
183eee772ecSBrian Somers 	  case IPPROTO_IPIP:
184944f7098SBrian Somers 	    cproto = P_UDP;
185cad7e742SBrian Somers 	    if (datalen < 8)	/* UDP header is 8 octets */
186cad7e742SBrian Somers 	      return (1);
187cad7e742SBrian Somers 	    uh = (const struct udphdr *) ptop;
188944f7098SBrian Somers 	    sport = ntohs(uh->uh_sport);
189944f7098SBrian Somers 	    dport = ntohs(uh->uh_dport);
19063f98b41SBrian Somers 	    estab = syn = finrst = -1;
191dd7e2610SBrian Somers 	    if (log_IsKept(LogDEBUG))
1928390b576SBrian Somers 	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
1938390b576SBrian Somers 		       sport, dport);
194af57ed9fSAtsushi Murai 	    break;
195af57ed9fSAtsushi Murai 	  case IPPROTO_TCP:
196944f7098SBrian Somers 	    cproto = P_TCP;
197cad7e742SBrian Somers 	    th = (const struct tcphdr *) ptop;
198cad7e742SBrian Somers 	    /* TCP headers are variable length.  The following code
199cad7e742SBrian Somers 	     * ensures that the TCP header length isn't de-referenced if
200cad7e742SBrian Somers 	     * the datagram is too short
201cad7e742SBrian Somers 	     */
202cad7e742SBrian Somers 	    if (datalen < 20 || datalen < (th->th_off << 2))
203cad7e742SBrian Somers 	      return (1);
204944f7098SBrian Somers 	    sport = ntohs(th->th_sport);
205944f7098SBrian Somers 	    dport = ntohs(th->th_dport);
206af57ed9fSAtsushi Murai 	    estab = (th->th_flags & TH_ACK);
20763f98b41SBrian Somers 	    syn = (th->th_flags & TH_SYN);
20863f98b41SBrian Somers 	    finrst = (th->th_flags & (TH_FIN|TH_RST));
2092b81c773SBrian Somers 	    if (log_IsKept(LogDEBUG)) {
2102b81c773SBrian Somers 	      if (!estab)
2118390b576SBrian Somers 		snprintf(dbuff, sizeof dbuff,
2128390b576SBrian Somers 			 "flags = %02x, sport = %d, dport = %d",
213927145beSBrian Somers 			 th->th_flags, sport, dport);
2142b81c773SBrian Somers 	      else
2152b81c773SBrian Somers 		*dbuff = '\0';
2162b81c773SBrian Somers 	    }
217af57ed9fSAtsushi Murai 	    break;
218af57ed9fSAtsushi Murai 	  default:
219cad7e742SBrian Somers 	    return (1);	/* We'll block unknown type of packet */
220af57ed9fSAtsushi Murai 	  }
221cad7e742SBrian Somers 
222dd7e2610SBrian Somers 	  if (log_IsKept(LogDEBUG)) {
2238390b576SBrian Somers 	    if (estab != -1) {
2248390b576SBrian Somers 	      len = strlen(dbuff);
22563f98b41SBrian Somers 	      snprintf(dbuff + len, sizeof dbuff - len,
22663f98b41SBrian Somers 		       ", estab = %d, syn = %d, finrst = %d",
22763f98b41SBrian Somers 		       estab, syn, finrst);
228af57ed9fSAtsushi Murai 	    }
229dd7e2610SBrian Somers 	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
2308390b576SBrian Somers 		       filter_Proto2Nam(cproto), dbuff);
2318390b576SBrian Somers 	  }
2328390b576SBrian Somers 	  gotinfo = 1;
2338390b576SBrian Somers 	}
234dd7e2610SBrian Somers 	if (log_IsKept(LogDEBUG)) {
235cad7e742SBrian Somers 	  if (fp->f_srcop != OP_NONE) {
2368390b576SBrian Somers 	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
237cad7e742SBrian Somers 		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
2388390b576SBrian Somers 	    len = strlen(dbuff);
2398390b576SBrian Somers 	  } else
2408390b576SBrian Somers 	    len = 0;
241cad7e742SBrian Somers 	  if (fp->f_dstop != OP_NONE) {
2428390b576SBrian Somers 	    snprintf(dbuff + len, sizeof dbuff - len,
243cad7e742SBrian Somers 		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
244cad7e742SBrian Somers 		     fp->f_dstport);
2458390b576SBrian Somers 	  } else if (!len)
2468390b576SBrian Somers 	    *dbuff = '\0';
2478390b576SBrian Somers 
248dd7e2610SBrian Somers 	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
2498390b576SBrian Somers 		     "check against proto %s%s, action = %s\n",
250cad7e742SBrian Somers 		     n, filter_Proto2Nam(fp->f_proto),
251cad7e742SBrian Somers 		     dbuff, filter_Action2Nam(fp->f_action));
2528390b576SBrian Somers 	}
253927145beSBrian Somers 
254cad7e742SBrian Somers 	if (cproto == fp->f_proto) {
255cad7e742SBrian Somers 	  if ((fp->f_srcop == OP_NONE ||
256cad7e742SBrian Somers 	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
257cad7e742SBrian Somers 	      (fp->f_dstop == OP_NONE ||
258cad7e742SBrian Somers 	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
259cad7e742SBrian Somers 	      (fp->f_estab == 0 || estab) &&
260cad7e742SBrian Somers 	      (fp->f_syn == 0 || syn) &&
261cad7e742SBrian Somers 	      (fp->f_finrst == 0 || finrst)) {
262cad7e742SBrian Somers 	    match = 1;
263af57ed9fSAtsushi Murai 	  }
264af57ed9fSAtsushi Murai 	}
265af57ed9fSAtsushi Murai       } else {
266cad7e742SBrian Somers 	/* Address is matched and no protocol specified. Make a decision. */
267dd7e2610SBrian Somers 	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
268cad7e742SBrian Somers 		   filter_Action2Nam(fp->f_action));
269cad7e742SBrian Somers 	match = 1;
270af57ed9fSAtsushi Murai       }
2718390b576SBrian Somers     } else
272dd7e2610SBrian Somers       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
273cad7e742SBrian Somers 
274cad7e742SBrian Somers     if (match != fp->f_invert) {
275cad7e742SBrian Somers       /* Take specified action */
276cad7e742SBrian Somers       if (fp->f_action < A_NONE)
277cad7e742SBrian Somers 	fp = &filter->rule[n = fp->f_action];
278cad7e742SBrian Somers       else
279cad7e742SBrian Somers 	return (fp->f_action != A_PERMIT);
280cad7e742SBrian Somers     } else {
281cad7e742SBrian Somers       n++;
282af57ed9fSAtsushi Murai       fp++;
283af57ed9fSAtsushi Murai     }
284af57ed9fSAtsushi Murai   }
285cad7e742SBrian Somers   return (1);		/* No rule is mached. Deny this packet */
286af57ed9fSAtsushi Murai }
287af57ed9fSAtsushi Murai 
2885ca5389aSBrian Somers #ifdef notdef
289af57ed9fSAtsushi Murai static void
290944f7098SBrian Somers IcmpError(struct ip *pip, int code)
291af57ed9fSAtsushi Murai {
292af57ed9fSAtsushi Murai   struct mbuf *bp;
293af57ed9fSAtsushi Murai 
294af57ed9fSAtsushi Murai   if (pip->ip_p != IPPROTO_ICMP) {
295dd7e2610SBrian Somers     bp = mbuf_Alloc(cnt, MB_IPIN);
29675240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, cnt);
297dd7e2610SBrian Somers     vj_SendFrame(bp);
2985828db6dSBrian Somers     ipcp_AddOutOctets(cnt);
2991ae349f5Scvs2svn   }
300af57ed9fSAtsushi Murai }
301af57ed9fSAtsushi Murai #endif
302af57ed9fSAtsushi Murai 
303af57ed9fSAtsushi Murai /*
304af57ed9fSAtsushi Murai  *  For debugging aid.
305af57ed9fSAtsushi Murai  */
306af57ed9fSAtsushi Murai int
3075ca5389aSBrian Somers PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
308af57ed9fSAtsushi Murai {
309af57ed9fSAtsushi Murai   struct ip *pip;
310af57ed9fSAtsushi Murai   struct tcphdr *th;
311af57ed9fSAtsushi Murai   struct udphdr *uh;
312af57ed9fSAtsushi Murai   struct icmp *icmph;
313af57ed9fSAtsushi Murai   char *ptop;
314af57ed9fSAtsushi Murai   int mask, len, n;
315442f8495SBrian Somers   int pri = 0;
31655a8cdeaSBrian Somers   int logit, loglen;
317d93d3a9cSBrian Somers   char logbuf[200];
318af57ed9fSAtsushi Murai 
319dd7e2610SBrian Somers   logit = log_IsKept(LogTCPIP) && filter->logok;
32055a8cdeaSBrian Somers   loglen = 0;
321af57ed9fSAtsushi Murai 
322af57ed9fSAtsushi Murai   pip = (struct ip *) cp;
323af57ed9fSAtsushi Murai 
32455a8cdeaSBrian Somers   if (logit && loglen < sizeof logbuf) {
3255ca5389aSBrian Somers     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
32655a8cdeaSBrian Somers     loglen += strlen(logbuf + loglen);
32755a8cdeaSBrian Somers   }
328af57ed9fSAtsushi Murai   ptop = (cp + (pip->ip_hl << 2));
329af57ed9fSAtsushi Murai 
330af57ed9fSAtsushi Murai   switch (pip->ip_p) {
331af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
33255a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
333af57ed9fSAtsushi Murai       icmph = (struct icmp *) ptop;
33455a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
33555a8cdeaSBrian Somers 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
33655a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
33755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
33855a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
33955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
340af57ed9fSAtsushi Murai     }
341af57ed9fSAtsushi Murai     break;
342da477886SBrian Somers 
343af57ed9fSAtsushi Murai   case IPPROTO_UDP:
344af57ed9fSAtsushi Murai     uh = (struct udphdr *) ptop;
345da477886SBrian Somers     if (pip->ip_tos == IPTOS_LOWDELAY)
346da477886SBrian Somers       pri++;
347da477886SBrian Somers 
348da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
349da477886SBrian Somers         ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
350da477886SBrian Somers                           ntohs(uh->uh_dport)))
351da477886SBrian Somers       pri++;
352da477886SBrian Somers 
353da477886SBrian Somers     if (logit && loglen < sizeof logbuf) {
35455a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
35555a8cdeaSBrian Somers 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
35655a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
35755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
35855a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
35955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
360af57ed9fSAtsushi Murai     }
361af57ed9fSAtsushi Murai     break;
362da477886SBrian Somers 
36362e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
3642faae814SBrian Somers   case IPPROTO_OSPFIGP:
3652faae814SBrian Somers     if (logit && loglen < sizeof logbuf) {
3662faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3672faae814SBrian Somers 	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
3682faae814SBrian Somers       loglen += strlen(logbuf + loglen);
3692faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3702faae814SBrian Somers 	       "%s", inet_ntoa(pip->ip_dst));
3712faae814SBrian Somers       loglen += strlen(logbuf + loglen);
3722faae814SBrian Somers     }
3732faae814SBrian Somers     break;
37462e85934SBrian Somers #endif
375da477886SBrian Somers 
376eee772ecSBrian Somers   case IPPROTO_IPIP:
377eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
378eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
379eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
380eee772ecSBrian Somers 	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
381eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
382eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
383eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
384eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
385eee772ecSBrian Somers     }
386eee772ecSBrian Somers     break;
387da477886SBrian Somers 
388eee772ecSBrian Somers   case IPPROTO_IGMP:
389eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
390eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
391eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
392eee772ecSBrian Somers 	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
393eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
394eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
395eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
396eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
397eee772ecSBrian Somers     }
398eee772ecSBrian Somers     break;
399da477886SBrian Somers 
400af57ed9fSAtsushi Murai   case IPPROTO_TCP:
401af57ed9fSAtsushi Murai     th = (struct tcphdr *) ptop;
402af57ed9fSAtsushi Murai     if (pip->ip_tos == IPTOS_LOWDELAY)
403442f8495SBrian Somers       pri++;
404da477886SBrian Somers 
405da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
406da477886SBrian Somers         ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
407442f8495SBrian Somers                           ntohs(th->th_dport)))
408442f8495SBrian Somers       pri++;
409442f8495SBrian Somers 
41055a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
411af57ed9fSAtsushi Murai       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
41255a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
41355a8cdeaSBrian Somers 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
41455a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
41555a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
41655a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
41755a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
418af57ed9fSAtsushi Murai       n = 0;
419af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
42055a8cdeaSBrian Somers 	if (th->th_flags & mask) {
42155a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
42255a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
42355a8cdeaSBrian Somers 	}
424af57ed9fSAtsushi Murai 	n++;
425af57ed9fSAtsushi Murai       }
42655a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
4273a2e4f62SBrian Somers 	       "  seq:%lx  ack:%lx (%d/%d)",
4283a2e4f62SBrian Somers 	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
42955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
430af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
431af57ed9fSAtsushi Murai 	u_short *sp;
432af57ed9fSAtsushi Murai 
433af57ed9fSAtsushi Murai 	ptop += 20;
434af57ed9fSAtsushi Murai 	sp = (u_short *) ptop;
43555a8cdeaSBrian Somers 	if (ntohs(sp[0]) == 0x0204) {
43655a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
43755a8cdeaSBrian Somers 		   " MSS = %d", ntohs(sp[1]));
43855a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
43955a8cdeaSBrian Somers 	}
440af57ed9fSAtsushi Murai       }
441af57ed9fSAtsushi Murai     }
442af57ed9fSAtsushi Murai     break;
443af57ed9fSAtsushi Murai   }
44476bd0c0aSDoug Rabson 
445cad7e742SBrian Somers   if (FilterCheck(pip, filter)) {
446710e9c29SBrian Somers     if (logit)
447dd7e2610SBrian Somers       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
4485ca5389aSBrian Somers #ifdef notdef
449944f7098SBrian Somers     if (direction == 0)
450944f7098SBrian Somers       IcmpError(pip, pri);
4515ca5389aSBrian Somers #endif
452af57ed9fSAtsushi Murai     return (-1);
453af57ed9fSAtsushi Murai   } else {
4545ca5389aSBrian Somers     /* Check Keep Alive filter */
455e43ebac1SBrian Somers     if (logit) {
456cad7e742SBrian Somers       if (FilterCheck(pip, &bundle->filter.alive))
457dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
4581e991daaSBrian Somers       else
459dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s\n", logbuf);
46053c9f6c0SAtsushi Murai     }
461af57ed9fSAtsushi Murai     return (pri);
462af57ed9fSAtsushi Murai   }
463af57ed9fSAtsushi Murai }
464af57ed9fSAtsushi Murai 
4655d9e6103SBrian Somers struct mbuf *
4665d9e6103SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
4677a6f8720SBrian Somers {
468af57ed9fSAtsushi Murai   int nb, nw;
469b6e82f33SBrian Somers   struct tun_data tun;
4705d9e6103SBrian Somers   struct ip *pip;
4715d9e6103SBrian Somers 
4725d9e6103SBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
4735d9e6103SBrian Somers     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
4745d9e6103SBrian Somers     mbuf_Free(bp);
4755d9e6103SBrian Somers     return NULL;
4765d9e6103SBrian Somers   }
477af57ed9fSAtsushi Murai 
478411675baSBrian Somers   mbuf_SetType(bp, MB_IPIN);
4796a6b4bbbSBrian Somers   tun_fill_header(tun, AF_INET);
4805d9e6103SBrian Somers   nb = mbuf_Length(bp);
48176d98538SBrian Somers   if (nb > sizeof tun.data) {
48276d98538SBrian Somers     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
48376d98538SBrian Somers                l->name, nb, (int)(sizeof tun.data));
48476d98538SBrian Somers     mbuf_Free(bp);
48576d98538SBrian Somers     return NULL;
48676d98538SBrian Somers   }
4875d9e6103SBrian Somers   mbuf_Read(bp, tun.data, nb);
488af57ed9fSAtsushi Murai 
4895d9e6103SBrian Somers   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
4905d9e6103SBrian Somers     return NULL;
4916db75539SBrian Somers 
4925d9e6103SBrian Somers   pip = (struct ip *)tun.data;
493cad7e742SBrian Somers   if (!FilterCheck(pip, &bundle->filter.alive))
4941e991daaSBrian Somers     bundle_StartIdleTimer(bundle);
4951e991daaSBrian Somers 
4965828db6dSBrian Somers   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
4971e991daaSBrian Somers 
49870ee81ffSBrian Somers   nb += sizeof tun - sizeof tun.data;
499faefde08SBrian Somers   nw = write(bundle->dev.fd, &tun, nb);
500c4c4aaacSBrian Somers   if (nw != nb) {
50157fd05c4SBrian Somers     if (nw == -1)
50276d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
50376d98538SBrian Somers                  l->name, nb, strerror(errno));
50457fd05c4SBrian Somers     else
50576d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
5066db75539SBrian Somers   }
5075d9e6103SBrian Somers 
5085d9e6103SBrian Somers   return NULL;
509af57ed9fSAtsushi Murai }
510af57ed9fSAtsushi Murai 
511af57ed9fSAtsushi Murai void
5125a72b6edSBrian Somers ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
513af57ed9fSAtsushi Murai {
514af57ed9fSAtsushi Murai   struct mbuf *bp;
515af57ed9fSAtsushi Murai 
516442f8495SBrian Somers   if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
5175a72b6edSBrian Somers     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
5185a72b6edSBrian Somers   else {
5195d9e6103SBrian Somers     /*
5205d9e6103SBrian Somers      * We allocate an extra 6 bytes, four at the front and two at the end.
5215d9e6103SBrian Somers      * This is an optimisation so that we need to do less work in
5225d9e6103SBrian Somers      * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
5235d9e6103SBrian Somers      * appending in hdlc_LayerPush().
5245d9e6103SBrian Somers      */
525411675baSBrian Somers     bp = mbuf_Alloc(count + 6, MB_IPOUT);
5265d9e6103SBrian Somers     bp->offset += 4;
5275d9e6103SBrian Somers     bp->cnt -= 6;
52875240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, count);
529442f8495SBrian Somers     mbuf_Enqueue(ipcp->Queue + pri, bp);
5305a72b6edSBrian Somers   }
531af57ed9fSAtsushi Murai }
532af57ed9fSAtsushi Murai 
5336f8e9f0aSBrian Somers void
5345a72b6edSBrian Somers ip_DeleteQueue(struct ipcp *ipcp)
5356f8e9f0aSBrian Somers {
5366f8e9f0aSBrian Somers   struct mqueue *queue;
5376f8e9f0aSBrian Somers 
538442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
5396f8e9f0aSBrian Somers     while (queue->top)
5406f8e9f0aSBrian Somers       mbuf_Free(mbuf_Dequeue(queue));
5416f8e9f0aSBrian Somers }
5426f8e9f0aSBrian Somers 
54384b8a6ebSAtsushi Murai int
5445a72b6edSBrian Somers ip_QueueLen(struct ipcp *ipcp)
54584b8a6ebSAtsushi Murai {
54684b8a6ebSAtsushi Murai   struct mqueue *queue;
547f4768038SBrian Somers   int result = 0;
548944f7098SBrian Somers 
549442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
550f4768038SBrian Somers     result += queue->qlen;
55184b8a6ebSAtsushi Murai 
552f4768038SBrian Somers   return result;
5531ae349f5Scvs2svn }
5541ae349f5Scvs2svn 
5553b0f8d2eSBrian Somers int
5565d9e6103SBrian Somers ip_PushPacket(struct link *l, struct bundle *bundle)
557af57ed9fSAtsushi Murai {
5585a72b6edSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
559af57ed9fSAtsushi Murai   struct mqueue *queue;
560af57ed9fSAtsushi Murai   struct mbuf *bp;
5615d9e6103SBrian Somers   struct ip *pip;
562274e766cSBrian Somers   int cnt;
563af57ed9fSAtsushi Murai 
5645a72b6edSBrian Somers   if (ipcp->fsm.state != ST_OPENED)
5653b0f8d2eSBrian Somers     return 0;
5661e991daaSBrian Somers 
567442f8495SBrian Somers   queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
568442f8495SBrian Somers   do {
569af57ed9fSAtsushi Murai     if (queue->top) {
570aad80d9fSBrian Somers       bp = mbuf_Contiguous(mbuf_Dequeue(queue));
571dd7e2610SBrian Somers       cnt = mbuf_Length(bp);
5725d9e6103SBrian Somers       pip = (struct ip *)MBUF_CTOP(bp);
573cad7e742SBrian Somers       if (!FilterCheck(pip, &bundle->filter.alive))
574ab886ad0SBrian Somers         bundle_StartIdleTimer(bundle);
575442f8495SBrian Somers       link_PushPacket(l, bp, bundle, 0, PROTO_IP);
5765a72b6edSBrian Somers       ipcp_AddOutOctets(ipcp, cnt);
5773b0f8d2eSBrian Somers       return 1;
578af57ed9fSAtsushi Murai     }
579442f8495SBrian Somers   } while (queue-- != ipcp->Queue);
5801e991daaSBrian Somers 
5813b0f8d2eSBrian Somers   return 0;
582af57ed9fSAtsushi Murai }
583