xref: /freebsd/usr.sbin/ppp/ip.c (revision 65309e5cda5d671cbca4763b481566ce387dcf7e)
165309e5cSBrian Somers /*-
265309e5cSBrian Somers  * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
365309e5cSBrian Somers  *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
465309e5cSBrian Somers  *                           Internet Initiative Japan, Inc (IIJ)
565309e5cSBrian Somers  * All rights reserved.
6af57ed9fSAtsushi Murai  *
765309e5cSBrian Somers  * Redistribution and use in source and binary forms, with or without
865309e5cSBrian Somers  * modification, are permitted provided that the following conditions
965309e5cSBrian Somers  * are met:
1065309e5cSBrian Somers  * 1. Redistributions of source code must retain the above copyright
1165309e5cSBrian Somers  *    notice, this list of conditions and the following disclaimer.
1265309e5cSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
1365309e5cSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
1465309e5cSBrian Somers  *    documentation and/or other materials provided with the distribution.
15af57ed9fSAtsushi Murai  *
1665309e5cSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1765309e5cSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1865309e5cSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1965309e5cSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2065309e5cSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2165309e5cSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2265309e5cSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2365309e5cSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2465309e5cSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2565309e5cSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2665309e5cSBrian Somers  * SUCH DAMAGE.
27af57ed9fSAtsushi Murai  *
2897d92980SPeter Wemm  * $FreeBSD$
29af57ed9fSAtsushi Murai  */
3065309e5cSBrian Somers 
31972a1bcfSBrian Somers #include <sys/param.h>
326a6b4bbbSBrian Somers #include <sys/socket.h>
3375240ed1SBrian Somers #include <netinet/in.h>
34af57ed9fSAtsushi Murai #include <netinet/in_systm.h>
35af57ed9fSAtsushi Murai #include <netinet/ip.h>
36af57ed9fSAtsushi Murai #include <netinet/ip_icmp.h>
37af57ed9fSAtsushi Murai #include <netinet/udp.h>
38af57ed9fSAtsushi Murai #include <netinet/tcp.h>
39ed6a16c1SPoul-Henning Kamp #include <arpa/inet.h>
401fa665f5SBrian Somers #include <sys/un.h>
4175240ed1SBrian Somers 
4257fd05c4SBrian Somers #include <errno.h>
4375240ed1SBrian Somers #include <stdio.h>
4475240ed1SBrian Somers #include <string.h>
455d9e6103SBrian Somers #include <termios.h>
4675240ed1SBrian Somers #include <unistd.h>
4775240ed1SBrian Somers 
485d9e6103SBrian Somers #include "layer.h"
495d9e6103SBrian Somers #include "proto.h"
50927145beSBrian Somers #include "mbuf.h"
51927145beSBrian Somers #include "log.h"
5275240ed1SBrian Somers #include "defs.h"
5375240ed1SBrian Somers #include "timer.h"
5475240ed1SBrian Somers #include "fsm.h"
55879ed6faSBrian Somers #include "lqr.h"
5675240ed1SBrian Somers #include "hdlc.h"
575828db6dSBrian Somers #include "throughput.h"
585828db6dSBrian Somers #include "iplist.h"
59eaa4df37SBrian Somers #include "slcompress.h"
6075240ed1SBrian Somers #include "ipcp.h"
611ae349f5Scvs2svn #include "filter.h"
622f786681SBrian Somers #include "descriptor.h"
6375240ed1SBrian Somers #include "lcp.h"
643b0f8d2eSBrian Somers #include "ccp.h"
653b0f8d2eSBrian Somers #include "link.h"
663b0f8d2eSBrian Somers #include "mp.h"
67972a1bcfSBrian Somers #ifndef NORADIUS
68972a1bcfSBrian Somers #include "radius.h"
69972a1bcfSBrian Somers #endif
707a6f8720SBrian Somers #include "bundle.h"
716a6b4bbbSBrian Somers #include "tun.h"
7275240ed1SBrian Somers #include "ip.h"
73af57ed9fSAtsushi Murai 
7452c9ca19SBrian Somers 
7552c9ca19SBrian Somers #define OPCODE_QUERY	0
7652c9ca19SBrian Somers #define OPCODE_IQUERY	1
7752c9ca19SBrian Somers #define OPCODE_STATUS	2
7852c9ca19SBrian Somers 
7952c9ca19SBrian Somers struct dns_header {
8052c9ca19SBrian Somers   u_short id;
8152c9ca19SBrian Somers   unsigned qr : 1;
8252c9ca19SBrian Somers   unsigned opcode : 4;
8352c9ca19SBrian Somers   unsigned aa : 1;
8452c9ca19SBrian Somers   unsigned tc : 1;
8552c9ca19SBrian Somers   unsigned rd : 1;
8652c9ca19SBrian Somers   unsigned ra : 1;
8752c9ca19SBrian Somers   unsigned z : 3;
8852c9ca19SBrian Somers   unsigned rcode : 4;
8952c9ca19SBrian Somers   u_short qdcount;
9052c9ca19SBrian Somers   u_short ancount;
9152c9ca19SBrian Somers   u_short nscount;
9252c9ca19SBrian Somers   u_short arcount;
93182c898aSBrian Somers };
94af57ed9fSAtsushi Murai 
9552c9ca19SBrian Somers static const char *
9652c9ca19SBrian Somers dns_Qclass2Txt(u_short qclass)
9752c9ca19SBrian Somers {
9852c9ca19SBrian Somers   static char failure[6];
9952c9ca19SBrian Somers   struct {
10052c9ca19SBrian Somers     u_short id;
10152c9ca19SBrian Somers     const char *txt;
10252c9ca19SBrian Somers   } qtxt[] = {
10352c9ca19SBrian Somers     /* rfc1035 */
10452c9ca19SBrian Somers     { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
10552c9ca19SBrian Somers   };
10652c9ca19SBrian Somers   int f;
10752c9ca19SBrian Somers 
10852c9ca19SBrian Somers   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
10952c9ca19SBrian Somers     if (qtxt[f].id == qclass)
11052c9ca19SBrian Somers       return qtxt[f].txt;
11152c9ca19SBrian Somers 
112d6d3eeabSBrian Somers   return HexStr(qclass, failure, sizeof failure);
11352c9ca19SBrian Somers }
11452c9ca19SBrian Somers 
11552c9ca19SBrian Somers static const char *
11652c9ca19SBrian Somers dns_Qtype2Txt(u_short qtype)
11752c9ca19SBrian Somers {
11852c9ca19SBrian Somers   static char failure[6];
11952c9ca19SBrian Somers   struct {
12052c9ca19SBrian Somers     u_short id;
12152c9ca19SBrian Somers     const char *txt;
12252c9ca19SBrian Somers   } qtxt[] = {
12352c9ca19SBrian Somers     /* rfc1035/rfc1700 */
12452c9ca19SBrian Somers     { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
12552c9ca19SBrian Somers     { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
12652c9ca19SBrian Somers     { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
12752c9ca19SBrian Somers     { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
12852c9ca19SBrian Somers     { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
12952c9ca19SBrian Somers     { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
13052c9ca19SBrian Somers     { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
13152c9ca19SBrian Somers     { 254, "MAILA" }, { 255, "*" }
13252c9ca19SBrian Somers   };
13352c9ca19SBrian Somers   int f;
13452c9ca19SBrian Somers 
13552c9ca19SBrian Somers   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
13652c9ca19SBrian Somers     if (qtxt[f].id == qtype)
13752c9ca19SBrian Somers       return qtxt[f].txt;
13852c9ca19SBrian Somers 
139d6d3eeabSBrian Somers   return HexStr(qtype, failure, sizeof failure);
14052c9ca19SBrian Somers }
14152c9ca19SBrian Somers 
142cad7e742SBrian Somers static __inline int
143944f7098SBrian Somers PortMatch(int op, u_short pport, u_short rport)
144af57ed9fSAtsushi Murai {
145af57ed9fSAtsushi Murai   switch (op) {
146af57ed9fSAtsushi Murai   case OP_EQ:
1470a4b6c5cSBrian Somers     return pport == rport;
148af57ed9fSAtsushi Murai   case OP_GT:
1490a4b6c5cSBrian Somers     return pport > rport;
150af57ed9fSAtsushi Murai   case OP_LT:
1510a4b6c5cSBrian Somers     return pport < rport;
152af57ed9fSAtsushi Murai   default:
1530a4b6c5cSBrian Somers     return 0;
154af57ed9fSAtsushi Murai   }
155af57ed9fSAtsushi Murai }
156af57ed9fSAtsushi Murai 
157af57ed9fSAtsushi Murai /*
1585d9e6103SBrian Somers  *  Check a packet against a defined filter
159cad7e742SBrian Somers  *  Returns 0 to accept the packet, non-zero to drop the packet
160cad7e742SBrian Somers  *
161cad7e742SBrian Somers  *  If filtering is enabled, the initial fragment of a datagram must
162cad7e742SBrian Somers  *  contain the complete protocol header, and subsequent fragments
163cad7e742SBrian Somers  *  must not attempt to over-write it.
164af57ed9fSAtsushi Murai  */
165af57ed9fSAtsushi Murai static int
1660a4b6c5cSBrian Somers FilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
167af57ed9fSAtsushi Murai {
168cad7e742SBrian Somers   int gotinfo;			/* true if IP payload decoded */
169cad7e742SBrian Somers   int cproto;			/* P_* protocol type if (gotinfo) */
170cad7e742SBrian Somers   int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
171cad7e742SBrian Somers   u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
172cad7e742SBrian Somers   int n;			/* filter rule to process */
173cad7e742SBrian Somers   int len;			/* bytes used in dbuff */
174cad7e742SBrian Somers   int didname;			/* true if filter header printed */
175cad7e742SBrian Somers   int match;			/* true if condition matched */
176cad7e742SBrian Somers   const struct filterent *fp = filter->rule;
17706a43ce0SBrian Somers   char dbuff[100], dstip[16];
178af57ed9fSAtsushi Murai 
179cad7e742SBrian Somers   if (fp->f_action == A_NONE)
1800a4b6c5cSBrian Somers     return 0;		/* No rule is given. Permit this packet */
181cad7e742SBrian Somers 
1820a4b6c5cSBrian Somers   /*
1830a4b6c5cSBrian Somers    * Deny any packet fragment that tries to over-write the header.
184cad7e742SBrian Somers    * Since we no longer have the real header available, punt on the
185cad7e742SBrian Somers    * largest normal header - 20 bytes for TCP without options, rounded
186cad7e742SBrian Somers    * up to the next possible fragment boundary.  Since the smallest
187cad7e742SBrian Somers    * `legal' MTU is 576, and the smallest recommended MTU is 296, any
1880a4b6c5cSBrian Somers    * fragmentation within this range is dubious at best
1890a4b6c5cSBrian Somers    */
190cad7e742SBrian Somers   len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
191cad7e742SBrian Somers   if (len > 0) {		/* Not first fragment within datagram */
19206a43ce0SBrian Somers     if (len < (24 >> 3)) {	/* don't allow fragment to over-write header */
19306a43ce0SBrian Somers       log_Printf(LogFILTER, " error: illegal header\n");
1940a4b6c5cSBrian Somers       return 1;
19506a43ce0SBrian Somers     }
196cad7e742SBrian Somers     /* permit fragments on in and out filter */
19706a43ce0SBrian Somers     if (!filter->fragok) {
19806a43ce0SBrian Somers       log_Printf(LogFILTER, " error: illegal fragmentation\n");
19906a43ce0SBrian Somers       return 1;
20006a43ce0SBrian Somers     } else
20106a43ce0SBrian Somers       return 0;
202cad7e742SBrian Somers   }
203cad7e742SBrian Somers 
20463f98b41SBrian Somers   cproto = gotinfo = estab = syn = finrst = didname = 0;
205af57ed9fSAtsushi Murai   sport = dport = 0;
206cad7e742SBrian Somers   for (n = 0; n < MAXFILTERS; ) {
207cad7e742SBrian Somers     if (fp->f_action == A_NONE) {
208cad7e742SBrian Somers       n++;
209cad7e742SBrian Somers       fp++;
210cad7e742SBrian Somers       continue;
211cad7e742SBrian Somers     }
2125ca5389aSBrian Somers 
213cad7e742SBrian Somers     if (!didname) {
214dd7e2610SBrian Somers       log_Printf(LogDEBUG, "%s filter:\n", filter->name);
2158390b576SBrian Somers       didname = 1;
216cad7e742SBrian Somers     }
2178390b576SBrian Somers 
218cad7e742SBrian Somers     match = 0;
219cad7e742SBrian Somers     if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
220cad7e742SBrian Somers           fp->f_src.mask.s_addr) &&
221cad7e742SBrian Somers         !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
222cad7e742SBrian Somers           fp->f_dst.mask.s_addr)) {
223cad7e742SBrian Somers       if (fp->f_proto != P_NONE) {
224af57ed9fSAtsushi Murai         if (!gotinfo) {
225cad7e742SBrian Somers           const char *ptop = (const char *) pip + (pip->ip_hl << 2);
226cad7e742SBrian Somers           const struct tcphdr *th;
227cad7e742SBrian Somers           const struct udphdr *uh;
228cad7e742SBrian Somers           const struct icmp *ih;
229cad7e742SBrian Somers           int datalen;	/* IP datagram length */
230af57ed9fSAtsushi Murai 
231cad7e742SBrian Somers           datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
232af57ed9fSAtsushi Murai           switch (pip->ip_p) {
233af57ed9fSAtsushi Murai           case IPPROTO_ICMP:
234944f7098SBrian Somers             cproto = P_ICMP;
23506a43ce0SBrian Somers             if (datalen < 8) {	/* ICMP must be at least 8 octets */
23606a43ce0SBrian Somers               log_Printf(LogFILTER, " error: ICMP must be at least 8 octets\n");
2370a4b6c5cSBrian Somers               return 1;
23806a43ce0SBrian Somers             }
23906a43ce0SBrian Somers 
240cad7e742SBrian Somers             ih = (const struct icmp *) ptop;
241944f7098SBrian Somers             sport = ih->icmp_type;
24263f98b41SBrian Somers             estab = syn = finrst = -1;
243dd7e2610SBrian Somers             if (log_IsKept(LogDEBUG))
2448390b576SBrian Somers               snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
245af57ed9fSAtsushi Murai             break;
246eee772ecSBrian Somers           case IPPROTO_IGMP:
2471f9e5fe5SBrian Somers             cproto = P_IGMP;
24806a43ce0SBrian Somers             if (datalen < 8) {	/* IGMP uses 8-octet messages */
24906a43ce0SBrian Somers               log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
2500a4b6c5cSBrian Somers               return 1;
25106a43ce0SBrian Somers             }
2521f9e5fe5SBrian Somers             estab = syn = finrst = -1;
2531f9e5fe5SBrian Somers             sport = ntohs(0);
2541f9e5fe5SBrian Somers             break;
25528149effSBrian Somers #ifdef IPPROTO_GRE
25628149effSBrian Somers           case IPPROTO_GRE:
25728149effSBrian Somers             cproto = P_GRE;
25806a43ce0SBrian Somers             if (datalen < 2) {    /* GRE uses 2-octet+ messages */
25906a43ce0SBrian Somers               log_Printf(LogFILTER, " error: GRE must be at least 2 octets\n");
2600a4b6c5cSBrian Somers               return 1;
26106a43ce0SBrian Somers             }
26228149effSBrian Somers             estab = syn = finrst = -1;
26328149effSBrian Somers             sport = ntohs(0);
26428149effSBrian Somers             break;
26528149effSBrian Somers #endif
26662e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
2672faae814SBrian Somers           case IPPROTO_OSPFIGP:
2682faae814SBrian Somers             cproto = P_OSPF;
26906a43ce0SBrian Somers             if (datalen < 8) {	/* IGMP uses 8-octet messages */
27006a43ce0SBrian Somers               log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
2710a4b6c5cSBrian Somers               return 1;
27206a43ce0SBrian Somers             }
2732faae814SBrian Somers             estab = syn = finrst = -1;
2742faae814SBrian Somers             sport = ntohs(0);
2752faae814SBrian Somers             break;
27662e85934SBrian Somers #endif
2772231246bSBrian Somers           case IPPROTO_ESP:
2782231246bSBrian Somers             cproto = P_ESP;
2792231246bSBrian Somers             estab = syn = finrst = -1;
2802231246bSBrian Somers             sport = ntohs(0);
2812231246bSBrian Somers             break;
2822231246bSBrian Somers           case IPPROTO_AH:
2832231246bSBrian Somers             cproto = P_AH;
2842231246bSBrian Somers             estab = syn = finrst = -1;
2852231246bSBrian Somers             sport = ntohs(0);
2862231246bSBrian Somers             break;
287eee772ecSBrian Somers           case IPPROTO_IPIP:
288da70ad60SBrian Somers             cproto = P_IPIP;
289da70ad60SBrian Somers             sport = dport = 0;
290da70ad60SBrian Somers             estab = syn = finrst = -1;
291da70ad60SBrian Somers             break;
292da70ad60SBrian Somers           case IPPROTO_UDP:
293944f7098SBrian Somers             cproto = P_UDP;
29406a43ce0SBrian Somers             if (datalen < 8) {	/* UDP header is 8 octets */
295da70ad60SBrian Somers               log_Printf(LogFILTER, " error: UDP/IPIP"
296da70ad60SBrian Somers                          " must be at least 8 octets\n");
2970a4b6c5cSBrian Somers               return 1;
29806a43ce0SBrian Somers             }
29906a43ce0SBrian Somers 
300cad7e742SBrian Somers             uh = (const struct udphdr *) ptop;
301944f7098SBrian Somers             sport = ntohs(uh->uh_sport);
302944f7098SBrian Somers             dport = ntohs(uh->uh_dport);
30363f98b41SBrian Somers             estab = syn = finrst = -1;
304dd7e2610SBrian Somers             if (log_IsKept(LogDEBUG))
3058390b576SBrian Somers               snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
3068390b576SBrian Somers                        sport, dport);
307af57ed9fSAtsushi Murai             break;
308af57ed9fSAtsushi Murai           case IPPROTO_TCP:
309944f7098SBrian Somers             cproto = P_TCP;
310cad7e742SBrian Somers             th = (const struct tcphdr *) ptop;
311cad7e742SBrian Somers             /* TCP headers are variable length.  The following code
312cad7e742SBrian Somers              * ensures that the TCP header length isn't de-referenced if
313cad7e742SBrian Somers              * the datagram is too short
314cad7e742SBrian Somers              */
31506a43ce0SBrian Somers             if (datalen < 20 || datalen < (th->th_off << 2)) {
31606a43ce0SBrian Somers               log_Printf(LogFILTER, " error: TCP header incorrect\n");
3170a4b6c5cSBrian Somers               return 1;
31806a43ce0SBrian Somers             }
319944f7098SBrian Somers             sport = ntohs(th->th_sport);
320944f7098SBrian Somers             dport = ntohs(th->th_dport);
321af57ed9fSAtsushi Murai             estab = (th->th_flags & TH_ACK);
32263f98b41SBrian Somers             syn = (th->th_flags & TH_SYN);
32363f98b41SBrian Somers             finrst = (th->th_flags & (TH_FIN|TH_RST));
3242b81c773SBrian Somers             if (log_IsKept(LogDEBUG)) {
3252b81c773SBrian Somers               if (!estab)
3268390b576SBrian Somers                 snprintf(dbuff, sizeof dbuff,
3278390b576SBrian Somers                          "flags = %02x, sport = %d, dport = %d",
328927145beSBrian Somers                          th->th_flags, sport, dport);
3292b81c773SBrian Somers               else
3302b81c773SBrian Somers                 *dbuff = '\0';
3312b81c773SBrian Somers             }
332af57ed9fSAtsushi Murai             break;
333af57ed9fSAtsushi Murai           default:
33406a43ce0SBrian Somers             log_Printf(LogFILTER, " error: unknown protocol\n");
3350a4b6c5cSBrian Somers             return 1;		/* We'll block unknown type of packet */
336af57ed9fSAtsushi Murai           }
337cad7e742SBrian Somers 
338dd7e2610SBrian Somers           if (log_IsKept(LogDEBUG)) {
3398390b576SBrian Somers             if (estab != -1) {
3408390b576SBrian Somers               len = strlen(dbuff);
34163f98b41SBrian Somers               snprintf(dbuff + len, sizeof dbuff - len,
34263f98b41SBrian Somers                        ", estab = %d, syn = %d, finrst = %d",
34363f98b41SBrian Somers                        estab, syn, finrst);
344af57ed9fSAtsushi Murai             }
345dd7e2610SBrian Somers             log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
3468390b576SBrian Somers                        filter_Proto2Nam(cproto), dbuff);
3478390b576SBrian Somers           }
3488390b576SBrian Somers           gotinfo = 1;
3498390b576SBrian Somers         }
350dd7e2610SBrian Somers         if (log_IsKept(LogDEBUG)) {
351cad7e742SBrian Somers           if (fp->f_srcop != OP_NONE) {
3528390b576SBrian Somers             snprintf(dbuff, sizeof dbuff, ", src %s %d",
353cad7e742SBrian Somers                      filter_Op2Nam(fp->f_srcop), fp->f_srcport);
3548390b576SBrian Somers             len = strlen(dbuff);
3558390b576SBrian Somers           } else
3568390b576SBrian Somers             len = 0;
357cad7e742SBrian Somers           if (fp->f_dstop != OP_NONE) {
3588390b576SBrian Somers             snprintf(dbuff + len, sizeof dbuff - len,
359cad7e742SBrian Somers                      ", dst %s %d", filter_Op2Nam(fp->f_dstop),
360cad7e742SBrian Somers                      fp->f_dstport);
3618390b576SBrian Somers           } else if (!len)
3628390b576SBrian Somers             *dbuff = '\0';
3638390b576SBrian Somers 
364dd7e2610SBrian Somers           log_Printf(LogDEBUG, "  rule = %d: Address match, "
3658390b576SBrian Somers                      "check against proto %s%s, action = %s\n",
366cad7e742SBrian Somers                      n, filter_Proto2Nam(fp->f_proto),
367cad7e742SBrian Somers                      dbuff, filter_Action2Nam(fp->f_action));
3688390b576SBrian Somers         }
369927145beSBrian Somers 
370cad7e742SBrian Somers         if (cproto == fp->f_proto) {
371cad7e742SBrian Somers           if ((fp->f_srcop == OP_NONE ||
372cad7e742SBrian Somers                PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
373cad7e742SBrian Somers               (fp->f_dstop == OP_NONE ||
374cad7e742SBrian Somers                PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
375cad7e742SBrian Somers               (fp->f_estab == 0 || estab) &&
376cad7e742SBrian Somers               (fp->f_syn == 0 || syn) &&
377cad7e742SBrian Somers               (fp->f_finrst == 0 || finrst)) {
378cad7e742SBrian Somers             match = 1;
379af57ed9fSAtsushi Murai           }
380af57ed9fSAtsushi Murai         }
381af57ed9fSAtsushi Murai       } else {
382cad7e742SBrian Somers         /* Address is matched and no protocol specified. Make a decision. */
383dd7e2610SBrian Somers         log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
384cad7e742SBrian Somers                    filter_Action2Nam(fp->f_action));
385cad7e742SBrian Somers         match = 1;
386af57ed9fSAtsushi Murai       }
3878390b576SBrian Somers     } else
388dd7e2610SBrian Somers       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
389cad7e742SBrian Somers 
390cad7e742SBrian Somers     if (match != fp->f_invert) {
391cad7e742SBrian Somers       /* Take specified action */
392cad7e742SBrian Somers       if (fp->f_action < A_NONE)
393cad7e742SBrian Somers         fp = &filter->rule[n = fp->f_action];
39406a43ce0SBrian Somers       else {
3950a4b6c5cSBrian Somers         if (fp->f_action == A_PERMIT) {
3960a4b6c5cSBrian Somers           if (psecs != NULL)
3970a4b6c5cSBrian Somers             *psecs = fp->timeout;
39806a43ce0SBrian Somers           if (strcmp(filter->name, "DIAL") == 0) {
39906a43ce0SBrian Somers             /* If dial filter then even print out accept packets */
40006a43ce0SBrian Somers             if (log_IsKept(LogFILTER)) {
40106a43ce0SBrian Somers               snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
40206a43ce0SBrian Somers               log_Printf(LogFILTER, "%sbound rule = %d accept %s "
40306a43ce0SBrian Somers                          "src = %s/%d dst = %s/%d\n",
40406a43ce0SBrian Somers                          filter->name, n, filter_Proto2Nam(cproto),
40506a43ce0SBrian Somers                          inet_ntoa(pip->ip_src), sport, dstip, dport);
40606a43ce0SBrian Somers             }
40706a43ce0SBrian Somers           }
4080a4b6c5cSBrian Somers           return 0;
40906a43ce0SBrian Somers         } else {
41006a43ce0SBrian Somers           if (log_IsKept(LogFILTER)) {
41106a43ce0SBrian Somers             snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
41206a43ce0SBrian Somers             log_Printf(LogFILTER,
41306a43ce0SBrian Somers                        "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
41406a43ce0SBrian Somers                        filter->name, n, filter_Proto2Nam(cproto),
41506a43ce0SBrian Somers                        inet_ntoa(pip->ip_src), sport, dstip, dport);
41606a43ce0SBrian Somers           }
4170a4b6c5cSBrian Somers           return 1;
41806a43ce0SBrian Somers         }		/* Explict math.  Deny this packet */
41906a43ce0SBrian Somers       }
420cad7e742SBrian Somers     } else {
421cad7e742SBrian Somers       n++;
422af57ed9fSAtsushi Murai       fp++;
423af57ed9fSAtsushi Murai     }
424af57ed9fSAtsushi Murai   }
42506a43ce0SBrian Somers 
42606a43ce0SBrian Somers   if (log_IsKept(LogFILTER)) {
42706a43ce0SBrian Somers     snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
42806a43ce0SBrian Somers     log_Printf(LogFILTER,
42906a43ce0SBrian Somers                "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
43006a43ce0SBrian Somers                filter->name, filter_Proto2Nam(cproto),
43106a43ce0SBrian Somers                inet_ntoa(pip->ip_src), sport, dstip, dport);
43206a43ce0SBrian Somers   }
43306a43ce0SBrian Somers 
4340a4b6c5cSBrian Somers   return 1;		/* No rule is mached. Deny this packet */
435af57ed9fSAtsushi Murai }
436af57ed9fSAtsushi Murai 
4375ca5389aSBrian Somers #ifdef notdef
438af57ed9fSAtsushi Murai static void
439944f7098SBrian Somers IcmpError(struct ip *pip, int code)
440af57ed9fSAtsushi Murai {
441af57ed9fSAtsushi Murai   struct mbuf *bp;
442af57ed9fSAtsushi Murai 
443af57ed9fSAtsushi Murai   if (pip->ip_p != IPPROTO_ICMP) {
44426af0ae9SBrian Somers     bp = m_get(m_len, MB_IPIN);
44526af0ae9SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, m_len);
446dd7e2610SBrian Somers     vj_SendFrame(bp);
44726af0ae9SBrian Somers     ipcp_AddOutOctets(m_len);
4481ae349f5Scvs2svn   }
449af57ed9fSAtsushi Murai }
450af57ed9fSAtsushi Murai #endif
451af57ed9fSAtsushi Murai 
45252c9ca19SBrian Somers static void
45352c9ca19SBrian Somers ip_LogDNS(const struct udphdr *uh, const char *direction)
45452c9ca19SBrian Somers {
45552c9ca19SBrian Somers   struct dns_header header;
45652c9ca19SBrian Somers   const u_short *pktptr;
45752c9ca19SBrian Somers   const u_char *ptr;
45847fe010cSBrian Somers   u_short *hptr, tmp;
45952c9ca19SBrian Somers   int len;
46052c9ca19SBrian Somers 
46152c9ca19SBrian Somers   ptr = (const char *)uh + sizeof *uh;
46252c9ca19SBrian Somers   len = ntohs(uh->uh_ulen) - sizeof *uh;
46352c9ca19SBrian Somers   if (len < sizeof header + 5)		/* rfc1024 */
46452c9ca19SBrian Somers     return;
46552c9ca19SBrian Somers 
46652c9ca19SBrian Somers   pktptr = (const u_short *)ptr;
46752c9ca19SBrian Somers   hptr = (u_short *)&header;
46852c9ca19SBrian Somers   ptr += sizeof header;
46952c9ca19SBrian Somers   len -= sizeof header;
47052c9ca19SBrian Somers 
47152c9ca19SBrian Somers   while (pktptr < (const u_short *)ptr) {
47252c9ca19SBrian Somers     *hptr++ = ntohs(*pktptr);		/* Careful of macro side-effects ! */
47352c9ca19SBrian Somers     pktptr++;
47452c9ca19SBrian Somers   }
47552c9ca19SBrian Somers 
47652c9ca19SBrian Somers   if (header.opcode == OPCODE_QUERY && header.qr == 0) {
47752c9ca19SBrian Somers     /* rfc1035 */
47826e6a622SBrian Somers     char namewithdot[MAXHOSTNAMELEN + 1], *n;
47952c9ca19SBrian Somers     const char *qtype, *qclass;
48052c9ca19SBrian Somers     const u_char *end;
48152c9ca19SBrian Somers 
48226e6a622SBrian Somers     n = namewithdot;
48352c9ca19SBrian Somers     end = ptr + len - 4;
48426e6a622SBrian Somers     if (end - ptr >= sizeof namewithdot)
48526e6a622SBrian Somers       end = ptr + sizeof namewithdot - 1;
48652c9ca19SBrian Somers     while (ptr < end) {
48752c9ca19SBrian Somers       len = *ptr++;
48852c9ca19SBrian Somers       if (len > end - ptr)
48952c9ca19SBrian Somers         len = end - ptr;
49026e6a622SBrian Somers       if (n != namewithdot)
49152c9ca19SBrian Somers         *n++ = '.';
49252c9ca19SBrian Somers       memcpy(n, ptr, len);
49352c9ca19SBrian Somers       ptr += len;
49452c9ca19SBrian Somers       n += len;
49552c9ca19SBrian Somers     }
49652c9ca19SBrian Somers     *n = '\0';
49747fe010cSBrian Somers 
49847fe010cSBrian Somers     if (log_IsKept(LogDNS)) {
49947fe010cSBrian Somers       memcpy(&tmp, end, sizeof tmp);
50047fe010cSBrian Somers       qtype = dns_Qtype2Txt(ntohs(tmp));
50147fe010cSBrian Somers       memcpy(&tmp, end + 2, sizeof tmp);
50247fe010cSBrian Somers       qclass = dns_Qclass2Txt(ntohs(tmp));
50352c9ca19SBrian Somers 
50452c9ca19SBrian Somers       log_Printf(LogDNS, "%sbound query %s %s %s\n",
50526e6a622SBrian Somers                  direction, qclass, qtype, namewithdot);
50652c9ca19SBrian Somers     }
50752c9ca19SBrian Somers   }
50847fe010cSBrian Somers }
50952c9ca19SBrian Somers 
510af57ed9fSAtsushi Murai /*
511af57ed9fSAtsushi Murai  *  For debugging aid.
512af57ed9fSAtsushi Murai  */
513af57ed9fSAtsushi Murai int
51498251667SBrian Somers PacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
5150a4b6c5cSBrian Somers             struct filter *filter, const char *prefix, unsigned *psecs)
516af57ed9fSAtsushi Murai {
51752c9ca19SBrian Somers   static const char *const TcpFlags[] = {
51852c9ca19SBrian Somers     "FIN", "SYN", "RST", "PSH", "ACK", "URG"
51952c9ca19SBrian Somers   };
520af57ed9fSAtsushi Murai   struct ip *pip;
521af57ed9fSAtsushi Murai   struct tcphdr *th;
522af57ed9fSAtsushi Murai   struct udphdr *uh;
523af57ed9fSAtsushi Murai   struct icmp *icmph;
52498251667SBrian Somers   unsigned char *ptop;
52552c9ca19SBrian Somers   int mask, len, n, pri, logit, loglen, result;
526d93d3a9cSBrian Somers   char logbuf[200];
527af57ed9fSAtsushi Murai 
528b565321aSBrian Somers   logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
529b565321aSBrian Somers           (!filter || filter->logok);
53055a8cdeaSBrian Somers   loglen = 0;
53152c9ca19SBrian Somers   pri = 0;
532af57ed9fSAtsushi Murai 
533af57ed9fSAtsushi Murai   pip = (struct ip *)cp;
53452c9ca19SBrian Somers   uh = NULL;
535af57ed9fSAtsushi Murai 
53655a8cdeaSBrian Somers   if (logit && loglen < sizeof logbuf) {
53798251667SBrian Somers     if (prefix)
53898251667SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix);
53998251667SBrian Somers     else if (filter)
5405ca5389aSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
541b565321aSBrian Somers     else
542b565321aSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
54355a8cdeaSBrian Somers     loglen += strlen(logbuf + loglen);
54455a8cdeaSBrian Somers   }
545af57ed9fSAtsushi Murai   ptop = (cp + (pip->ip_hl << 2));
546af57ed9fSAtsushi Murai 
547af57ed9fSAtsushi Murai   switch (pip->ip_p) {
548af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
54955a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
55098251667SBrian Somers       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *icmph;
551af57ed9fSAtsushi Murai       icmph = (struct icmp *) ptop;
55255a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
55355a8cdeaSBrian Somers                "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
55455a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
55555a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
55698251667SBrian Somers                "%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), icmph->icmp_type,
55798251667SBrian Somers                len, nb);
55855a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
559af57ed9fSAtsushi Murai     }
560af57ed9fSAtsushi Murai     break;
561da477886SBrian Somers 
562af57ed9fSAtsushi Murai   case IPPROTO_UDP:
563af57ed9fSAtsushi Murai     uh = (struct udphdr *) ptop;
5644c240437SBrian Somers     if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
565da477886SBrian Somers       pri++;
566da477886SBrian Somers 
567da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
568da477886SBrian Somers         ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
569da477886SBrian Somers                           ntohs(uh->uh_dport)))
570da477886SBrian Somers       pri++;
571da477886SBrian Somers 
572da477886SBrian Somers     if (logit && loglen < sizeof logbuf) {
57398251667SBrian Somers       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *uh;
57455a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
57555a8cdeaSBrian Somers                "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
57655a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
57755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
57898251667SBrian Somers                "%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport),
57998251667SBrian Somers                len, nb);
58055a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
581af57ed9fSAtsushi Murai     }
58298251667SBrian Somers 
58398251667SBrian Somers     if (Enabled(bundle, OPT_FILTERDECAP) &&
58498251667SBrian Somers         ptop[sizeof *uh] == HDLC_ADDR && ptop[sizeof *uh + 1] == HDLC_UI) {
58598251667SBrian Somers       u_short proto;
58698251667SBrian Somers       const char *type;
58798251667SBrian Somers 
58898251667SBrian Somers       memcpy(&proto, ptop + sizeof *uh + 2, sizeof proto);
58998251667SBrian Somers       type = NULL;
59098251667SBrian Somers 
59198251667SBrian Somers       switch (ntohs(proto)) {
59298251667SBrian Somers         case PROTO_IP:
59398251667SBrian Somers           snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
59498251667SBrian Somers           result = PacketCheck(bundle, ptop + sizeof *uh + 4,
59598251667SBrian Somers                                nb - (ptop - cp) - sizeof *uh - 4, filter,
5960a4b6c5cSBrian Somers                                logbuf, psecs);
59798251667SBrian Somers           if (result != -2)
59898251667SBrian Somers               return result;
59998251667SBrian Somers           type = "IP";
60098251667SBrian Somers           break;
60198251667SBrian Somers 
60298251667SBrian Somers         case PROTO_VJUNCOMP: type = "compressed VJ";   break;
60398251667SBrian Somers         case PROTO_VJCOMP:   type = "uncompressed VJ"; break;
60498251667SBrian Somers         case PROTO_MP:       type = "Multi-link"; break;
60598251667SBrian Somers         case PROTO_ICOMPD:   type = "Individual link CCP"; break;
60698251667SBrian Somers         case PROTO_COMPD:    type = "CCP"; break;
60798251667SBrian Somers         case PROTO_IPCP:     type = "IPCP"; break;
60898251667SBrian Somers         case PROTO_LCP:      type = "LCP"; break;
60998251667SBrian Somers         case PROTO_PAP:      type = "PAP"; break;
61098251667SBrian Somers         case PROTO_CBCP:     type = "CBCP"; break;
61198251667SBrian Somers         case PROTO_LQR:      type = "LQR"; break;
61298251667SBrian Somers         case PROTO_CHAP:     type = "CHAP"; break;
61398251667SBrian Somers       }
61498251667SBrian Somers       if (type) {
61598251667SBrian Somers         snprintf(logbuf + loglen, sizeof logbuf - loglen,
61698251667SBrian Somers                  " - %s data", type);
61798251667SBrian Somers         loglen += strlen(logbuf + loglen);
61898251667SBrian Somers       }
61998251667SBrian Somers     }
62098251667SBrian Somers 
621af57ed9fSAtsushi Murai     break;
622da477886SBrian Somers 
62328149effSBrian Somers #ifdef IPPROTO_GRE
62428149effSBrian Somers   case IPPROTO_GRE:
62528149effSBrian Somers     if (logit && loglen < sizeof logbuf) {
62698251667SBrian Somers       len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
62728149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
62828149effSBrian Somers           "GRE: %s ---> ", inet_ntoa(pip->ip_src));
62928149effSBrian Somers       loglen += strlen(logbuf + loglen);
63028149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
63198251667SBrian Somers               "%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
63228149effSBrian Somers       loglen += strlen(logbuf + loglen);
63328149effSBrian Somers     }
63428149effSBrian Somers     break;
63528149effSBrian Somers #endif
63628149effSBrian Somers 
63762e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
6382faae814SBrian Somers   case IPPROTO_OSPFIGP:
6392faae814SBrian Somers     if (logit && loglen < sizeof logbuf) {
64098251667SBrian Somers       len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
6412faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
6422faae814SBrian Somers                "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
6432faae814SBrian Somers       loglen += strlen(logbuf + loglen);
6442faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
64598251667SBrian Somers                "%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
6462faae814SBrian Somers       loglen += strlen(logbuf + loglen);
6472faae814SBrian Somers     }
6482faae814SBrian Somers     break;
64962e85934SBrian Somers #endif
650da477886SBrian Somers 
651eee772ecSBrian Somers   case IPPROTO_IPIP:
652eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
653eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
654da70ad60SBrian Somers                "IPIP: %s ---> ", inet_ntoa(pip->ip_src));
655eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
656eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
657da70ad60SBrian Somers                "%s", inet_ntoa(pip->ip_dst));
658eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
659da70ad60SBrian Somers 
660da70ad60SBrian Somers       if (((struct ip *)ptop)->ip_v == 4) {
661da70ad60SBrian Somers         snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
662da70ad60SBrian Somers         result = PacketCheck(bundle, ptop, nb - (ptop - cp), filter,
663da70ad60SBrian Somers                              logbuf, psecs);
664da70ad60SBrian Somers         if (result != -2)
665da70ad60SBrian Somers           return result;
666da70ad60SBrian Somers       }
667eee772ecSBrian Somers     }
668eee772ecSBrian Somers     break;
669da477886SBrian Somers 
6702231246bSBrian Somers   case IPPROTO_ESP:
6712231246bSBrian Somers     if (logit && loglen < sizeof logbuf) {
6722231246bSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
6732231246bSBrian Somers                "ESP: %s ---> ", inet_ntoa(pip->ip_src));
6742231246bSBrian Somers       loglen += strlen(logbuf + loglen);
67525254215SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
67625254215SBrian Somers                inet_ntoa(pip->ip_dst), ptop);
6772231246bSBrian Somers       loglen += strlen(logbuf + loglen);
6782231246bSBrian Somers     }
6792231246bSBrian Somers     break;
6802231246bSBrian Somers 
6812231246bSBrian Somers   case IPPROTO_AH:
6822231246bSBrian Somers     if (logit && loglen < sizeof logbuf) {
6832231246bSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
6842231246bSBrian Somers                "AH: %s ---> ", inet_ntoa(pip->ip_src));
6852231246bSBrian Somers       loglen += strlen(logbuf + loglen);
68625254215SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
68725254215SBrian Somers                inet_ntoa(pip->ip_dst), ptop + sizeof(u_int32_t));
6882231246bSBrian Somers       loglen += strlen(logbuf + loglen);
6892231246bSBrian Somers     }
6902231246bSBrian Somers     break;
6912231246bSBrian Somers 
692eee772ecSBrian Somers   case IPPROTO_IGMP:
693eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
694eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
695eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
6960a4b6c5cSBrian Somers                "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src),
6970a4b6c5cSBrian Somers                ntohs(uh->uh_sport));
698eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
699eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
700eee772ecSBrian Somers                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
701eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
702eee772ecSBrian Somers     }
703eee772ecSBrian Somers     break;
704da477886SBrian Somers 
705af57ed9fSAtsushi Murai   case IPPROTO_TCP:
706af57ed9fSAtsushi Murai     th = (struct tcphdr *) ptop;
7074c240437SBrian Somers     if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
708442f8495SBrian Somers       pri++;
709da477886SBrian Somers 
710da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
711da477886SBrian Somers         ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
712442f8495SBrian Somers                           ntohs(th->th_dport)))
713442f8495SBrian Somers       pri++;
714442f8495SBrian Somers 
71555a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
716af57ed9fSAtsushi Murai       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
71755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
71855a8cdeaSBrian Somers            "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
71955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
72055a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
72155a8cdeaSBrian Somers                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
72255a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
723af57ed9fSAtsushi Murai       n = 0;
724af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
72555a8cdeaSBrian Somers         if (th->th_flags & mask) {
72655a8cdeaSBrian Somers           snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
72755a8cdeaSBrian Somers           loglen += strlen(logbuf + loglen);
72855a8cdeaSBrian Somers         }
729af57ed9fSAtsushi Murai         n++;
730af57ed9fSAtsushi Murai       }
73155a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
7323a2e4f62SBrian Somers                "  seq:%lx  ack:%lx (%d/%d)",
7333a2e4f62SBrian Somers                (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
73455a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
735af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
736af57ed9fSAtsushi Murai         u_short *sp;
737af57ed9fSAtsushi Murai 
738af57ed9fSAtsushi Murai         ptop += 20;
739af57ed9fSAtsushi Murai         sp = (u_short *) ptop;
74055a8cdeaSBrian Somers         if (ntohs(sp[0]) == 0x0204) {
74155a8cdeaSBrian Somers           snprintf(logbuf + loglen, sizeof logbuf - loglen,
74255a8cdeaSBrian Somers                    " MSS = %d", ntohs(sp[1]));
74355a8cdeaSBrian Somers           loglen += strlen(logbuf + loglen);
74455a8cdeaSBrian Somers         }
745af57ed9fSAtsushi Murai       }
746af57ed9fSAtsushi Murai     }
747af57ed9fSAtsushi Murai     break;
74898251667SBrian Somers 
74998251667SBrian Somers   default:
75098251667SBrian Somers     if (prefix)
75198251667SBrian Somers       return -2;
752af57ed9fSAtsushi Murai   }
75376bd0c0aSDoug Rabson 
7540a4b6c5cSBrian Somers   if (filter && FilterCheck(pip, filter, psecs)) {
755710e9c29SBrian Somers     if (logit)
756dd7e2610SBrian Somers       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
7575ca5389aSBrian Somers #ifdef notdef
758944f7098SBrian Somers     if (direction == 0)
759944f7098SBrian Somers       IcmpError(pip, pri);
7605ca5389aSBrian Somers #endif
76152c9ca19SBrian Somers     result = -1;
762af57ed9fSAtsushi Murai   } else {
7635ca5389aSBrian Somers     /* Check Keep Alive filter */
76452c9ca19SBrian Somers     if (logit && log_IsKept(LogTCPIP)) {
7650a4b6c5cSBrian Somers       unsigned alivesecs;
7660a4b6c5cSBrian Somers 
7670a4b6c5cSBrian Somers       alivesecs = 0;
7680a4b6c5cSBrian Somers       if (filter && FilterCheck(pip, &bundle->filter.alive, &alivesecs))
769dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
7700a4b6c5cSBrian Somers       else if (psecs != NULL) {
7710a4b6c5cSBrian Somers         if(*psecs == 0)
7720a4b6c5cSBrian Somers           *psecs = alivesecs;
7730a4b6c5cSBrian Somers         if (*psecs) {
7740a4b6c5cSBrian Somers           if (*psecs != alivesecs)
7750a4b6c5cSBrian Somers             log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n",
7760a4b6c5cSBrian Somers                        logbuf, *psecs, alivesecs);
7771e991daaSBrian Somers           else
7780a4b6c5cSBrian Somers             log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs);
7790a4b6c5cSBrian Somers         } else
780dd7e2610SBrian Somers           log_Printf(LogTCPIP, "%s\n", logbuf);
78153c9f6c0SAtsushi Murai       }
7820a4b6c5cSBrian Somers     }
78352c9ca19SBrian Somers     result = pri;
784af57ed9fSAtsushi Murai   }
78552c9ca19SBrian Somers 
786b565321aSBrian Somers   if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
78752c9ca19SBrian Somers     ip_LogDNS(uh, filter->name);
78852c9ca19SBrian Somers 
78952c9ca19SBrian Somers   return result;
790af57ed9fSAtsushi Murai }
791af57ed9fSAtsushi Murai 
7925d9e6103SBrian Somers struct mbuf *
7935d9e6103SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
7947a6f8720SBrian Somers {
795af57ed9fSAtsushi Murai   int nb, nw;
796b6e82f33SBrian Somers   struct tun_data tun;
7975d9e6103SBrian Somers   struct ip *pip;
7983a7b6d76SBrian Somers   char *data;
7990a4b6c5cSBrian Somers   unsigned secs, alivesecs;
8005d9e6103SBrian Somers 
8015d9e6103SBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
8025d9e6103SBrian Somers     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
80326af0ae9SBrian Somers     m_freem(bp);
8045d9e6103SBrian Somers     return NULL;
8055d9e6103SBrian Somers   }
806af57ed9fSAtsushi Murai 
80726af0ae9SBrian Somers   m_settype(bp, MB_IPIN);
80826af0ae9SBrian Somers   nb = m_length(bp);
80976d98538SBrian Somers   if (nb > sizeof tun.data) {
81076d98538SBrian Somers     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
81176d98538SBrian Somers                l->name, nb, (int)(sizeof tun.data));
81226af0ae9SBrian Somers     m_freem(bp);
81376d98538SBrian Somers     return NULL;
81476d98538SBrian Somers   }
8155d9e6103SBrian Somers   mbuf_Read(bp, tun.data, nb);
816af57ed9fSAtsushi Murai 
8170a4b6c5cSBrian Somers   secs = 0;
8180a4b6c5cSBrian Somers   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in, NULL, &secs) < 0)
8195d9e6103SBrian Somers     return NULL;
8206db75539SBrian Somers 
8215d9e6103SBrian Somers   pip = (struct ip *)tun.data;
8220a4b6c5cSBrian Somers   alivesecs = 0;
8230a4b6c5cSBrian Somers   if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
8240a4b6c5cSBrian Somers     if (secs == 0)
8250a4b6c5cSBrian Somers       secs = alivesecs;
8260a4b6c5cSBrian Somers     bundle_StartIdleTimer(bundle, secs);
8270a4b6c5cSBrian Somers   }
8281e991daaSBrian Somers 
8295828db6dSBrian Somers   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
8301e991daaSBrian Somers 
8313a7b6d76SBrian Somers   if (bundle->dev.header) {
8320a4b6c5cSBrian Somers     tun.header.family = htonl(AF_INET);
83370ee81ffSBrian Somers     nb += sizeof tun - sizeof tun.data;
8343a7b6d76SBrian Somers     data = (char *)&tun;
8353a7b6d76SBrian Somers   } else
8363a7b6d76SBrian Somers     data = tun.data;
8373a7b6d76SBrian Somers 
8383a7b6d76SBrian Somers   nw = write(bundle->dev.fd, data, nb);
839c4c4aaacSBrian Somers   if (nw != nb) {
84057fd05c4SBrian Somers     if (nw == -1)
84176d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
84276d98538SBrian Somers                  l->name, nb, strerror(errno));
84357fd05c4SBrian Somers     else
84476d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
8456db75539SBrian Somers   }
8465d9e6103SBrian Somers 
8475d9e6103SBrian Somers   return NULL;
848af57ed9fSAtsushi Murai }
849af57ed9fSAtsushi Murai 
850af57ed9fSAtsushi Murai void
8515a72b6edSBrian Somers ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
852af57ed9fSAtsushi Murai {
853af57ed9fSAtsushi Murai   struct mbuf *bp;
854af57ed9fSAtsushi Murai 
855442f8495SBrian Somers   if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
8565a72b6edSBrian Somers     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
8575a72b6edSBrian Somers   else {
8585d9e6103SBrian Somers     /*
8595d9e6103SBrian Somers      * We allocate an extra 6 bytes, four at the front and two at the end.
8605d9e6103SBrian Somers      * This is an optimisation so that we need to do less work in
86126af0ae9SBrian Somers      * m_prepend() in acf_LayerPush() and proto_LayerPush() and
8625d9e6103SBrian Somers      * appending in hdlc_LayerPush().
8635d9e6103SBrian Somers      */
86426af0ae9SBrian Somers     bp = m_get(count + 6, MB_IPOUT);
86526af0ae9SBrian Somers     bp->m_offset += 4;
86626af0ae9SBrian Somers     bp->m_len -= 6;
86775240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, count);
86826af0ae9SBrian Somers     m_enqueue(ipcp->Queue + pri, bp);
8695a72b6edSBrian Somers   }
870af57ed9fSAtsushi Murai }
871af57ed9fSAtsushi Murai 
8726f8e9f0aSBrian Somers void
8735a72b6edSBrian Somers ip_DeleteQueue(struct ipcp *ipcp)
8746f8e9f0aSBrian Somers {
8756f8e9f0aSBrian Somers   struct mqueue *queue;
8766f8e9f0aSBrian Somers 
877442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
8786f8e9f0aSBrian Somers     while (queue->top)
87926af0ae9SBrian Somers       m_freem(m_dequeue(queue));
8806f8e9f0aSBrian Somers }
8816f8e9f0aSBrian Somers 
88226af0ae9SBrian Somers size_t
8835a72b6edSBrian Somers ip_QueueLen(struct ipcp *ipcp)
88484b8a6ebSAtsushi Murai {
88584b8a6ebSAtsushi Murai   struct mqueue *queue;
88626af0ae9SBrian Somers   size_t result;
887944f7098SBrian Somers 
88826af0ae9SBrian Somers   result = 0;
889442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
89026af0ae9SBrian Somers     result += queue->len;
89184b8a6ebSAtsushi Murai 
892f4768038SBrian Somers   return result;
8931ae349f5Scvs2svn }
8941ae349f5Scvs2svn 
8953b0f8d2eSBrian Somers int
8965d9e6103SBrian Somers ip_PushPacket(struct link *l, struct bundle *bundle)
897af57ed9fSAtsushi Murai {
8985a72b6edSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
899af57ed9fSAtsushi Murai   struct mqueue *queue;
900af57ed9fSAtsushi Murai   struct mbuf *bp;
9015d9e6103SBrian Somers   struct ip *pip;
90226af0ae9SBrian Somers   int m_len;
9030a4b6c5cSBrian Somers   u_int32_t secs = 0;
9040a4b6c5cSBrian Somers   unsigned alivesecs = 0;
905af57ed9fSAtsushi Murai 
9065a72b6edSBrian Somers   if (ipcp->fsm.state != ST_OPENED)
9073b0f8d2eSBrian Somers     return 0;
9081e991daaSBrian Somers 
909442f8495SBrian Somers   queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
910442f8495SBrian Somers   do {
911af57ed9fSAtsushi Murai     if (queue->top) {
9120a4b6c5cSBrian Somers       bp = m_dequeue(queue);
9130a4b6c5cSBrian Somers       bp = mbuf_Read(bp, &secs, sizeof secs);
9140a4b6c5cSBrian Somers       bp = m_pullup(bp);
91526af0ae9SBrian Somers       m_len = m_length(bp);
9165d9e6103SBrian Somers       pip = (struct ip *)MBUF_CTOP(bp);
9170a4b6c5cSBrian Somers       if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
9180a4b6c5cSBrian Somers         if (secs == 0)
9190a4b6c5cSBrian Somers           secs = alivesecs;
9200a4b6c5cSBrian Somers         bundle_StartIdleTimer(bundle, secs);
9210a4b6c5cSBrian Somers       }
922442f8495SBrian Somers       link_PushPacket(l, bp, bundle, 0, PROTO_IP);
92326af0ae9SBrian Somers       ipcp_AddOutOctets(ipcp, m_len);
9243b0f8d2eSBrian Somers       return 1;
925af57ed9fSAtsushi Murai     }
926442f8495SBrian Somers   } while (queue-- != ipcp->Queue);
9271e991daaSBrian Somers 
9283b0f8d2eSBrian Somers   return 0;
929af57ed9fSAtsushi Murai }
930