xref: /freebsd/usr.sbin/ppp/ip.c (revision 26af0ae96638b0453bcc87cae6031eb0b3988171)
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 */
1244d9d17feSBrian 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;
17328149effSBrian Somers #ifdef IPPROTO_GRE
17428149effSBrian Somers           case IPPROTO_GRE:
17528149effSBrian Somers             cproto = P_GRE;
17628149effSBrian Somers             if (datalen < 2)    /* GRE uses 2-octet+ messages */
17728149effSBrian Somers               return (1);
17828149effSBrian Somers             estab = syn = finrst = -1;
17928149effSBrian Somers             sport = ntohs(0);
18028149effSBrian Somers             break;
18128149effSBrian Somers #endif
18262e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
1832faae814SBrian Somers 	  case IPPROTO_OSPFIGP:
1842faae814SBrian Somers 	    cproto = P_OSPF;
1852faae814SBrian Somers 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
1862faae814SBrian Somers 	      return (1);
1872faae814SBrian Somers 	    estab = syn = finrst = -1;
1882faae814SBrian Somers 	    sport = ntohs(0);
1892faae814SBrian Somers 	    break;
19062e85934SBrian Somers #endif
1911f9e5fe5SBrian Somers 	  case IPPROTO_UDP:
192eee772ecSBrian Somers 	  case IPPROTO_IPIP:
193944f7098SBrian Somers 	    cproto = P_UDP;
194cad7e742SBrian Somers 	    if (datalen < 8)	/* UDP header is 8 octets */
195cad7e742SBrian Somers 	      return (1);
196cad7e742SBrian Somers 	    uh = (const struct udphdr *) ptop;
197944f7098SBrian Somers 	    sport = ntohs(uh->uh_sport);
198944f7098SBrian Somers 	    dport = ntohs(uh->uh_dport);
19963f98b41SBrian Somers 	    estab = syn = finrst = -1;
200dd7e2610SBrian Somers 	    if (log_IsKept(LogDEBUG))
2018390b576SBrian Somers 	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
2028390b576SBrian Somers 		       sport, dport);
203af57ed9fSAtsushi Murai 	    break;
204af57ed9fSAtsushi Murai 	  case IPPROTO_TCP:
205944f7098SBrian Somers 	    cproto = P_TCP;
206cad7e742SBrian Somers 	    th = (const struct tcphdr *) ptop;
207cad7e742SBrian Somers 	    /* TCP headers are variable length.  The following code
208cad7e742SBrian Somers 	     * ensures that the TCP header length isn't de-referenced if
209cad7e742SBrian Somers 	     * the datagram is too short
210cad7e742SBrian Somers 	     */
211cad7e742SBrian Somers 	    if (datalen < 20 || datalen < (th->th_off << 2))
212cad7e742SBrian Somers 	      return (1);
213944f7098SBrian Somers 	    sport = ntohs(th->th_sport);
214944f7098SBrian Somers 	    dport = ntohs(th->th_dport);
215af57ed9fSAtsushi Murai 	    estab = (th->th_flags & TH_ACK);
21663f98b41SBrian Somers 	    syn = (th->th_flags & TH_SYN);
21763f98b41SBrian Somers 	    finrst = (th->th_flags & (TH_FIN|TH_RST));
2182b81c773SBrian Somers 	    if (log_IsKept(LogDEBUG)) {
2192b81c773SBrian Somers 	      if (!estab)
2208390b576SBrian Somers 		snprintf(dbuff, sizeof dbuff,
2218390b576SBrian Somers 			 "flags = %02x, sport = %d, dport = %d",
222927145beSBrian Somers 			 th->th_flags, sport, dport);
2232b81c773SBrian Somers 	      else
2242b81c773SBrian Somers 		*dbuff = '\0';
2252b81c773SBrian Somers 	    }
226af57ed9fSAtsushi Murai 	    break;
227af57ed9fSAtsushi Murai 	  default:
228cad7e742SBrian Somers 	    return (1);	/* We'll block unknown type of packet */
229af57ed9fSAtsushi Murai 	  }
230cad7e742SBrian Somers 
231dd7e2610SBrian Somers 	  if (log_IsKept(LogDEBUG)) {
2328390b576SBrian Somers 	    if (estab != -1) {
2338390b576SBrian Somers 	      len = strlen(dbuff);
23463f98b41SBrian Somers 	      snprintf(dbuff + len, sizeof dbuff - len,
23563f98b41SBrian Somers 		       ", estab = %d, syn = %d, finrst = %d",
23663f98b41SBrian Somers 		       estab, syn, finrst);
237af57ed9fSAtsushi Murai 	    }
238dd7e2610SBrian Somers 	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
2398390b576SBrian Somers 		       filter_Proto2Nam(cproto), dbuff);
2408390b576SBrian Somers 	  }
2418390b576SBrian Somers 	  gotinfo = 1;
2428390b576SBrian Somers 	}
243dd7e2610SBrian Somers 	if (log_IsKept(LogDEBUG)) {
244cad7e742SBrian Somers 	  if (fp->f_srcop != OP_NONE) {
2458390b576SBrian Somers 	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
246cad7e742SBrian Somers 		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
2478390b576SBrian Somers 	    len = strlen(dbuff);
2488390b576SBrian Somers 	  } else
2498390b576SBrian Somers 	    len = 0;
250cad7e742SBrian Somers 	  if (fp->f_dstop != OP_NONE) {
2518390b576SBrian Somers 	    snprintf(dbuff + len, sizeof dbuff - len,
252cad7e742SBrian Somers 		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
253cad7e742SBrian Somers 		     fp->f_dstport);
2548390b576SBrian Somers 	  } else if (!len)
2558390b576SBrian Somers 	    *dbuff = '\0';
2568390b576SBrian Somers 
257dd7e2610SBrian Somers 	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
2588390b576SBrian Somers 		     "check against proto %s%s, action = %s\n",
259cad7e742SBrian Somers 		     n, filter_Proto2Nam(fp->f_proto),
260cad7e742SBrian Somers 		     dbuff, filter_Action2Nam(fp->f_action));
2618390b576SBrian Somers 	}
262927145beSBrian Somers 
263cad7e742SBrian Somers 	if (cproto == fp->f_proto) {
264cad7e742SBrian Somers 	  if ((fp->f_srcop == OP_NONE ||
265cad7e742SBrian Somers 	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
266cad7e742SBrian Somers 	      (fp->f_dstop == OP_NONE ||
267cad7e742SBrian Somers 	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
268cad7e742SBrian Somers 	      (fp->f_estab == 0 || estab) &&
269cad7e742SBrian Somers 	      (fp->f_syn == 0 || syn) &&
270cad7e742SBrian Somers 	      (fp->f_finrst == 0 || finrst)) {
271cad7e742SBrian Somers 	    match = 1;
272af57ed9fSAtsushi Murai 	  }
273af57ed9fSAtsushi Murai 	}
274af57ed9fSAtsushi Murai       } else {
275cad7e742SBrian Somers 	/* Address is matched and no protocol specified. Make a decision. */
276dd7e2610SBrian Somers 	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
277cad7e742SBrian Somers 		   filter_Action2Nam(fp->f_action));
278cad7e742SBrian Somers 	match = 1;
279af57ed9fSAtsushi Murai       }
2808390b576SBrian Somers     } else
281dd7e2610SBrian Somers       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
282cad7e742SBrian Somers 
283cad7e742SBrian Somers     if (match != fp->f_invert) {
284cad7e742SBrian Somers       /* Take specified action */
285cad7e742SBrian Somers       if (fp->f_action < A_NONE)
286cad7e742SBrian Somers 	fp = &filter->rule[n = fp->f_action];
287cad7e742SBrian Somers       else
288cad7e742SBrian Somers 	return (fp->f_action != A_PERMIT);
289cad7e742SBrian Somers     } else {
290cad7e742SBrian Somers       n++;
291af57ed9fSAtsushi Murai       fp++;
292af57ed9fSAtsushi Murai     }
293af57ed9fSAtsushi Murai   }
294cad7e742SBrian Somers   return (1);		/* No rule is mached. Deny this packet */
295af57ed9fSAtsushi Murai }
296af57ed9fSAtsushi Murai 
2975ca5389aSBrian Somers #ifdef notdef
298af57ed9fSAtsushi Murai static void
299944f7098SBrian Somers IcmpError(struct ip *pip, int code)
300af57ed9fSAtsushi Murai {
301af57ed9fSAtsushi Murai   struct mbuf *bp;
302af57ed9fSAtsushi Murai 
303af57ed9fSAtsushi Murai   if (pip->ip_p != IPPROTO_ICMP) {
30426af0ae9SBrian Somers     bp = m_get(m_len, MB_IPIN);
30526af0ae9SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, m_len);
306dd7e2610SBrian Somers     vj_SendFrame(bp);
30726af0ae9SBrian Somers     ipcp_AddOutOctets(m_len);
3081ae349f5Scvs2svn   }
309af57ed9fSAtsushi Murai }
310af57ed9fSAtsushi Murai #endif
311af57ed9fSAtsushi Murai 
312af57ed9fSAtsushi Murai /*
313af57ed9fSAtsushi Murai  *  For debugging aid.
314af57ed9fSAtsushi Murai  */
315af57ed9fSAtsushi Murai int
3165ca5389aSBrian Somers PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
317af57ed9fSAtsushi Murai {
318af57ed9fSAtsushi Murai   struct ip *pip;
319af57ed9fSAtsushi Murai   struct tcphdr *th;
320af57ed9fSAtsushi Murai   struct udphdr *uh;
321af57ed9fSAtsushi Murai   struct icmp *icmph;
322af57ed9fSAtsushi Murai   char *ptop;
323af57ed9fSAtsushi Murai   int mask, len, n;
324442f8495SBrian Somers   int pri = 0;
32555a8cdeaSBrian Somers   int logit, loglen;
326d93d3a9cSBrian Somers   char logbuf[200];
327af57ed9fSAtsushi Murai 
328dd7e2610SBrian Somers   logit = log_IsKept(LogTCPIP) && filter->logok;
32955a8cdeaSBrian Somers   loglen = 0;
330af57ed9fSAtsushi Murai 
331af57ed9fSAtsushi Murai   pip = (struct ip *) cp;
332af57ed9fSAtsushi Murai 
33355a8cdeaSBrian Somers   if (logit && loglen < sizeof logbuf) {
3345ca5389aSBrian Somers     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
33555a8cdeaSBrian Somers     loglen += strlen(logbuf + loglen);
33655a8cdeaSBrian Somers   }
337af57ed9fSAtsushi Murai   ptop = (cp + (pip->ip_hl << 2));
338af57ed9fSAtsushi Murai 
339af57ed9fSAtsushi Murai   switch (pip->ip_p) {
340af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
34155a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
342af57ed9fSAtsushi Murai       icmph = (struct icmp *) ptop;
34355a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
34455a8cdeaSBrian Somers 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
34555a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
34655a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
34755a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
34855a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
349af57ed9fSAtsushi Murai     }
350af57ed9fSAtsushi Murai     break;
351da477886SBrian Somers 
352af57ed9fSAtsushi Murai   case IPPROTO_UDP:
353af57ed9fSAtsushi Murai     uh = (struct udphdr *) ptop;
354da477886SBrian Somers     if (pip->ip_tos == IPTOS_LOWDELAY)
355da477886SBrian Somers       pri++;
356da477886SBrian Somers 
357da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
358da477886SBrian Somers         ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
359da477886SBrian Somers                           ntohs(uh->uh_dport)))
360da477886SBrian Somers       pri++;
361da477886SBrian Somers 
362da477886SBrian Somers     if (logit && loglen < sizeof logbuf) {
36355a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
36455a8cdeaSBrian Somers 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
36555a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
36655a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
36755a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
36855a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
369af57ed9fSAtsushi Murai     }
370af57ed9fSAtsushi Murai     break;
371da477886SBrian Somers 
37228149effSBrian Somers #ifdef IPPROTO_GRE
37328149effSBrian Somers   case IPPROTO_GRE:
37428149effSBrian Somers     if (logit && loglen < sizeof logbuf) {
37528149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
37628149effSBrian Somers           "GRE: %s ---> ", inet_ntoa(pip->ip_src));
37728149effSBrian Somers       loglen += strlen(logbuf + loglen);
37828149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
37928149effSBrian Somers               "%s", inet_ntoa(pip->ip_dst));
38028149effSBrian Somers       loglen += strlen(logbuf + loglen);
38128149effSBrian Somers     }
38228149effSBrian Somers     break;
38328149effSBrian Somers #endif
38428149effSBrian Somers 
38562e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
3862faae814SBrian Somers   case IPPROTO_OSPFIGP:
3872faae814SBrian Somers     if (logit && loglen < sizeof logbuf) {
3882faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3892faae814SBrian Somers 	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
3902faae814SBrian Somers       loglen += strlen(logbuf + loglen);
3912faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3922faae814SBrian Somers 	       "%s", inet_ntoa(pip->ip_dst));
3932faae814SBrian Somers       loglen += strlen(logbuf + loglen);
3942faae814SBrian Somers     }
3952faae814SBrian Somers     break;
39662e85934SBrian Somers #endif
397da477886SBrian Somers 
398eee772ecSBrian Somers   case IPPROTO_IPIP:
399eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
400eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
401eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
402eee772ecSBrian Somers 	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
403eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
404eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
405eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
406eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
407eee772ecSBrian Somers     }
408eee772ecSBrian Somers     break;
409da477886SBrian Somers 
410eee772ecSBrian Somers   case IPPROTO_IGMP:
411eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
412eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
413eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
414eee772ecSBrian Somers 	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
415eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
416eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
417eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
418eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
419eee772ecSBrian Somers     }
420eee772ecSBrian Somers     break;
421da477886SBrian Somers 
422af57ed9fSAtsushi Murai   case IPPROTO_TCP:
423af57ed9fSAtsushi Murai     th = (struct tcphdr *) ptop;
424af57ed9fSAtsushi Murai     if (pip->ip_tos == IPTOS_LOWDELAY)
425442f8495SBrian Somers       pri++;
426da477886SBrian Somers 
427da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
428da477886SBrian Somers         ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
429442f8495SBrian Somers                           ntohs(th->th_dport)))
430442f8495SBrian Somers       pri++;
431442f8495SBrian Somers 
43255a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
433af57ed9fSAtsushi Murai       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
43455a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
43555a8cdeaSBrian Somers 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
43655a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
43755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
43855a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
43955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
440af57ed9fSAtsushi Murai       n = 0;
441af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
44255a8cdeaSBrian Somers 	if (th->th_flags & mask) {
44355a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
44455a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
44555a8cdeaSBrian Somers 	}
446af57ed9fSAtsushi Murai 	n++;
447af57ed9fSAtsushi Murai       }
44855a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
4493a2e4f62SBrian Somers 	       "  seq:%lx  ack:%lx (%d/%d)",
4503a2e4f62SBrian Somers 	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
45155a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
452af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
453af57ed9fSAtsushi Murai 	u_short *sp;
454af57ed9fSAtsushi Murai 
455af57ed9fSAtsushi Murai 	ptop += 20;
456af57ed9fSAtsushi Murai 	sp = (u_short *) ptop;
45755a8cdeaSBrian Somers 	if (ntohs(sp[0]) == 0x0204) {
45855a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
45955a8cdeaSBrian Somers 		   " MSS = %d", ntohs(sp[1]));
46055a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
46155a8cdeaSBrian Somers 	}
462af57ed9fSAtsushi Murai       }
463af57ed9fSAtsushi Murai     }
464af57ed9fSAtsushi Murai     break;
465af57ed9fSAtsushi Murai   }
46676bd0c0aSDoug Rabson 
467cad7e742SBrian Somers   if (FilterCheck(pip, filter)) {
468710e9c29SBrian Somers     if (logit)
469dd7e2610SBrian Somers       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
4705ca5389aSBrian Somers #ifdef notdef
471944f7098SBrian Somers     if (direction == 0)
472944f7098SBrian Somers       IcmpError(pip, pri);
4735ca5389aSBrian Somers #endif
474af57ed9fSAtsushi Murai     return (-1);
475af57ed9fSAtsushi Murai   } else {
4765ca5389aSBrian Somers     /* Check Keep Alive filter */
477e43ebac1SBrian Somers     if (logit) {
478cad7e742SBrian Somers       if (FilterCheck(pip, &bundle->filter.alive))
479dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
4801e991daaSBrian Somers       else
481dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s\n", logbuf);
48253c9f6c0SAtsushi Murai     }
483af57ed9fSAtsushi Murai     return (pri);
484af57ed9fSAtsushi Murai   }
485af57ed9fSAtsushi Murai }
486af57ed9fSAtsushi Murai 
4875d9e6103SBrian Somers struct mbuf *
4885d9e6103SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
4897a6f8720SBrian Somers {
490af57ed9fSAtsushi Murai   int nb, nw;
491b6e82f33SBrian Somers   struct tun_data tun;
4925d9e6103SBrian Somers   struct ip *pip;
4935d9e6103SBrian Somers 
4945d9e6103SBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
4955d9e6103SBrian Somers     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
49626af0ae9SBrian Somers     m_freem(bp);
4975d9e6103SBrian Somers     return NULL;
4985d9e6103SBrian Somers   }
499af57ed9fSAtsushi Murai 
50026af0ae9SBrian Somers   m_settype(bp, MB_IPIN);
5016a6b4bbbSBrian Somers   tun_fill_header(tun, AF_INET);
50226af0ae9SBrian Somers   nb = m_length(bp);
50376d98538SBrian Somers   if (nb > sizeof tun.data) {
50476d98538SBrian Somers     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
50576d98538SBrian Somers                l->name, nb, (int)(sizeof tun.data));
50626af0ae9SBrian Somers     m_freem(bp);
50776d98538SBrian Somers     return NULL;
50876d98538SBrian Somers   }
5095d9e6103SBrian Somers   mbuf_Read(bp, tun.data, nb);
510af57ed9fSAtsushi Murai 
5115d9e6103SBrian Somers   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
5125d9e6103SBrian Somers     return NULL;
5136db75539SBrian Somers 
5145d9e6103SBrian Somers   pip = (struct ip *)tun.data;
515cad7e742SBrian Somers   if (!FilterCheck(pip, &bundle->filter.alive))
5161e991daaSBrian Somers     bundle_StartIdleTimer(bundle);
5171e991daaSBrian Somers 
5185828db6dSBrian Somers   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
5191e991daaSBrian Somers 
52070ee81ffSBrian Somers   nb += sizeof tun - sizeof tun.data;
521faefde08SBrian Somers   nw = write(bundle->dev.fd, &tun, nb);
522c4c4aaacSBrian Somers   if (nw != nb) {
52357fd05c4SBrian Somers     if (nw == -1)
52476d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
52576d98538SBrian Somers                  l->name, nb, strerror(errno));
52657fd05c4SBrian Somers     else
52776d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
5286db75539SBrian Somers   }
5295d9e6103SBrian Somers 
5305d9e6103SBrian Somers   return NULL;
531af57ed9fSAtsushi Murai }
532af57ed9fSAtsushi Murai 
533af57ed9fSAtsushi Murai void
5345a72b6edSBrian Somers ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
535af57ed9fSAtsushi Murai {
536af57ed9fSAtsushi Murai   struct mbuf *bp;
537af57ed9fSAtsushi Murai 
538442f8495SBrian Somers   if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
5395a72b6edSBrian Somers     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
5405a72b6edSBrian Somers   else {
5415d9e6103SBrian Somers     /*
5425d9e6103SBrian Somers      * We allocate an extra 6 bytes, four at the front and two at the end.
5435d9e6103SBrian Somers      * This is an optimisation so that we need to do less work in
54426af0ae9SBrian Somers      * m_prepend() in acf_LayerPush() and proto_LayerPush() and
5455d9e6103SBrian Somers      * appending in hdlc_LayerPush().
5465d9e6103SBrian Somers      */
54726af0ae9SBrian Somers     bp = m_get(count + 6, MB_IPOUT);
54826af0ae9SBrian Somers     bp->m_offset += 4;
54926af0ae9SBrian Somers     bp->m_len -= 6;
55075240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, count);
55126af0ae9SBrian Somers     m_enqueue(ipcp->Queue + pri, bp);
5525a72b6edSBrian Somers   }
553af57ed9fSAtsushi Murai }
554af57ed9fSAtsushi Murai 
5556f8e9f0aSBrian Somers void
5565a72b6edSBrian Somers ip_DeleteQueue(struct ipcp *ipcp)
5576f8e9f0aSBrian Somers {
5586f8e9f0aSBrian Somers   struct mqueue *queue;
5596f8e9f0aSBrian Somers 
560442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
5616f8e9f0aSBrian Somers     while (queue->top)
56226af0ae9SBrian Somers       m_freem(m_dequeue(queue));
5636f8e9f0aSBrian Somers }
5646f8e9f0aSBrian Somers 
56526af0ae9SBrian Somers size_t
5665a72b6edSBrian Somers ip_QueueLen(struct ipcp *ipcp)
56784b8a6ebSAtsushi Murai {
56884b8a6ebSAtsushi Murai   struct mqueue *queue;
56926af0ae9SBrian Somers   size_t result;
570944f7098SBrian Somers 
57126af0ae9SBrian Somers   result = 0;
572442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
57326af0ae9SBrian Somers     result += queue->len;
57484b8a6ebSAtsushi Murai 
575f4768038SBrian Somers   return result;
5761ae349f5Scvs2svn }
5771ae349f5Scvs2svn 
5783b0f8d2eSBrian Somers int
5795d9e6103SBrian Somers ip_PushPacket(struct link *l, struct bundle *bundle)
580af57ed9fSAtsushi Murai {
5815a72b6edSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
582af57ed9fSAtsushi Murai   struct mqueue *queue;
583af57ed9fSAtsushi Murai   struct mbuf *bp;
5845d9e6103SBrian Somers   struct ip *pip;
58526af0ae9SBrian Somers   int m_len;
586af57ed9fSAtsushi Murai 
5875a72b6edSBrian Somers   if (ipcp->fsm.state != ST_OPENED)
5883b0f8d2eSBrian Somers     return 0;
5891e991daaSBrian Somers 
590442f8495SBrian Somers   queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
591442f8495SBrian Somers   do {
592af57ed9fSAtsushi Murai     if (queue->top) {
59326af0ae9SBrian Somers       bp = m_pullup(m_dequeue(queue));
59426af0ae9SBrian Somers       m_len = m_length(bp);
5955d9e6103SBrian Somers       pip = (struct ip *)MBUF_CTOP(bp);
596cad7e742SBrian Somers       if (!FilterCheck(pip, &bundle->filter.alive))
597ab886ad0SBrian Somers         bundle_StartIdleTimer(bundle);
598442f8495SBrian Somers       link_PushPacket(l, bp, bundle, 0, PROTO_IP);
59926af0ae9SBrian Somers       ipcp_AddOutOctets(ipcp, m_len);
6003b0f8d2eSBrian Somers       return 1;
601af57ed9fSAtsushi Murai     }
602442f8495SBrian Somers   } while (queue-- != ipcp->Queue);
6031e991daaSBrian Somers 
6043b0f8d2eSBrian Somers   return 0;
605af57ed9fSAtsushi Murai }
606