xref: /freebsd/usr.sbin/ppp/ip.c (revision 1136c6ac64148317a4496e6f447bc81640bcbb82)
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>
3630949fd4SBrian Somers #ifndef NOINET6
3730949fd4SBrian Somers #include <netinet/icmp6.h>
3830949fd4SBrian Somers #include <netinet/ip6.h>
3930949fd4SBrian Somers #endif
40af57ed9fSAtsushi Murai #include <netinet/ip_icmp.h>
41af57ed9fSAtsushi Murai #include <netinet/udp.h>
42af57ed9fSAtsushi Murai #include <netinet/tcp.h>
43ed6a16c1SPoul-Henning Kamp #include <arpa/inet.h>
441fa665f5SBrian Somers #include <sys/un.h>
4575240ed1SBrian Somers 
4657fd05c4SBrian Somers #include <errno.h>
4730949fd4SBrian Somers #include <netdb.h>
4875240ed1SBrian Somers #include <stdio.h>
4930949fd4SBrian Somers #include <stdlib.h>
5075240ed1SBrian Somers #include <string.h>
515d9e6103SBrian Somers #include <termios.h>
5275240ed1SBrian Somers #include <unistd.h>
5375240ed1SBrian Somers 
545d9e6103SBrian Somers #include "layer.h"
555d9e6103SBrian Somers #include "proto.h"
56927145beSBrian Somers #include "mbuf.h"
57927145beSBrian Somers #include "log.h"
5875240ed1SBrian Somers #include "defs.h"
5975240ed1SBrian Somers #include "timer.h"
6075240ed1SBrian Somers #include "fsm.h"
61879ed6faSBrian Somers #include "lqr.h"
6275240ed1SBrian Somers #include "hdlc.h"
635828db6dSBrian Somers #include "throughput.h"
645828db6dSBrian Somers #include "iplist.h"
65eaa4df37SBrian Somers #include "slcompress.h"
6630949fd4SBrian Somers #include "ncpaddr.h"
6730949fd4SBrian Somers #include "ip.h"
6875240ed1SBrian Somers #include "ipcp.h"
691ae349f5Scvs2svn #include "filter.h"
702f786681SBrian Somers #include "descriptor.h"
7175240ed1SBrian Somers #include "lcp.h"
723b0f8d2eSBrian Somers #include "ccp.h"
733b0f8d2eSBrian Somers #include "link.h"
743b0f8d2eSBrian Somers #include "mp.h"
75972a1bcfSBrian Somers #ifndef NORADIUS
76972a1bcfSBrian Somers #include "radius.h"
77972a1bcfSBrian Somers #endif
7830949fd4SBrian Somers #include "ipv6cp.h"
7930949fd4SBrian Somers #include "ncp.h"
807a6f8720SBrian Somers #include "bundle.h"
816a6b4bbbSBrian Somers #include "tun.h"
82af57ed9fSAtsushi Murai 
8352c9ca19SBrian Somers 
8452c9ca19SBrian Somers #define OPCODE_QUERY	0
8552c9ca19SBrian Somers #define OPCODE_IQUERY	1
8652c9ca19SBrian Somers #define OPCODE_STATUS	2
8752c9ca19SBrian Somers 
8852c9ca19SBrian Somers struct dns_header {
8952c9ca19SBrian Somers   u_short id;
9052c9ca19SBrian Somers   unsigned qr : 1;
9152c9ca19SBrian Somers   unsigned opcode : 4;
9252c9ca19SBrian Somers   unsigned aa : 1;
9352c9ca19SBrian Somers   unsigned tc : 1;
9452c9ca19SBrian Somers   unsigned rd : 1;
9552c9ca19SBrian Somers   unsigned ra : 1;
9652c9ca19SBrian Somers   unsigned z : 3;
9752c9ca19SBrian Somers   unsigned rcode : 4;
9852c9ca19SBrian Somers   u_short qdcount;
9952c9ca19SBrian Somers   u_short ancount;
10052c9ca19SBrian Somers   u_short nscount;
10152c9ca19SBrian Somers   u_short arcount;
102182c898aSBrian Somers };
103af57ed9fSAtsushi Murai 
10452c9ca19SBrian Somers static const char *
10552c9ca19SBrian Somers dns_Qclass2Txt(u_short qclass)
10652c9ca19SBrian Somers {
10752c9ca19SBrian Somers   static char failure[6];
10852c9ca19SBrian Somers   struct {
10952c9ca19SBrian Somers     u_short id;
11052c9ca19SBrian Somers     const char *txt;
11152c9ca19SBrian Somers   } qtxt[] = {
11252c9ca19SBrian Somers     /* rfc1035 */
11352c9ca19SBrian Somers     { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
11452c9ca19SBrian Somers   };
11552c9ca19SBrian Somers   int f;
11652c9ca19SBrian Somers 
11752c9ca19SBrian Somers   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
11852c9ca19SBrian Somers     if (qtxt[f].id == qclass)
11952c9ca19SBrian Somers       return qtxt[f].txt;
12052c9ca19SBrian Somers 
121d6d3eeabSBrian Somers   return HexStr(qclass, failure, sizeof failure);
12252c9ca19SBrian Somers }
12352c9ca19SBrian Somers 
12452c9ca19SBrian Somers static const char *
12552c9ca19SBrian Somers dns_Qtype2Txt(u_short qtype)
12652c9ca19SBrian Somers {
12752c9ca19SBrian Somers   static char failure[6];
12852c9ca19SBrian Somers   struct {
12952c9ca19SBrian Somers     u_short id;
13052c9ca19SBrian Somers     const char *txt;
13152c9ca19SBrian Somers   } qtxt[] = {
13252c9ca19SBrian Somers     /* rfc1035/rfc1700 */
13352c9ca19SBrian Somers     { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
13452c9ca19SBrian Somers     { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
13552c9ca19SBrian Somers     { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
13652c9ca19SBrian Somers     { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
13752c9ca19SBrian Somers     { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
13852c9ca19SBrian Somers     { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
13952c9ca19SBrian Somers     { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
14052c9ca19SBrian Somers     { 254, "MAILA" }, { 255, "*" }
14152c9ca19SBrian Somers   };
14252c9ca19SBrian Somers   int f;
14352c9ca19SBrian Somers 
14452c9ca19SBrian Somers   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
14552c9ca19SBrian Somers     if (qtxt[f].id == qtype)
14652c9ca19SBrian Somers       return qtxt[f].txt;
14752c9ca19SBrian Somers 
148d6d3eeabSBrian Somers   return HexStr(qtype, failure, sizeof failure);
14952c9ca19SBrian Somers }
15052c9ca19SBrian Somers 
151cad7e742SBrian Somers static __inline int
152944f7098SBrian Somers PortMatch(int op, u_short pport, u_short rport)
153af57ed9fSAtsushi Murai {
154af57ed9fSAtsushi Murai   switch (op) {
155af57ed9fSAtsushi Murai   case OP_EQ:
1560a4b6c5cSBrian Somers     return pport == rport;
157af57ed9fSAtsushi Murai   case OP_GT:
1580a4b6c5cSBrian Somers     return pport > rport;
159af57ed9fSAtsushi Murai   case OP_LT:
1600a4b6c5cSBrian Somers     return pport < rport;
161af57ed9fSAtsushi Murai   default:
1620a4b6c5cSBrian Somers     return 0;
163af57ed9fSAtsushi Murai   }
164af57ed9fSAtsushi Murai }
165af57ed9fSAtsushi Murai 
166af57ed9fSAtsushi Murai /*
16730949fd4SBrian Somers  * Check a packet against the given filter
16830949fd4SBrian Somers  * Returns 0 to accept the packet, non-zero to drop the packet.
16930949fd4SBrian Somers  * If psecs is not NULL, populate it with the timeout associated
17030949fd4SBrian Somers  * with the filter rule matched.
171cad7e742SBrian Somers  *
172cad7e742SBrian Somers  * If filtering is enabled, the initial fragment of a datagram must
173cad7e742SBrian Somers  * contain the complete protocol header, and subsequent fragments
174cad7e742SBrian Somers  * must not attempt to over-write it.
17530949fd4SBrian Somers  *
17630949fd4SBrian Somers  * One (and only one) of pip or pip6 must be set.
177af57ed9fSAtsushi Murai  */
17830949fd4SBrian Somers int
17930949fd4SBrian Somers FilterCheck(const unsigned char *packet, u_int32_t family,
18030949fd4SBrian Somers             const struct filter *filter, unsigned *psecs)
181af57ed9fSAtsushi Murai {
182cad7e742SBrian Somers   int gotinfo;			/* true if IP payload decoded */
18330949fd4SBrian Somers   int cproto;			/* IPPROTO_* protocol number if (gotinfo) */
184cad7e742SBrian Somers   int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
185cad7e742SBrian Somers   u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
186cad7e742SBrian Somers   int n;			/* filter rule to process */
187cad7e742SBrian Somers   int len;			/* bytes used in dbuff */
188cad7e742SBrian Somers   int didname;			/* true if filter header printed */
189cad7e742SBrian Somers   int match;			/* true if condition matched */
19030949fd4SBrian Somers   int mindata;			/* minimum data size or zero */
191cad7e742SBrian Somers   const struct filterent *fp = filter->rule;
19230949fd4SBrian Somers   char dbuff[100], dstip[16], prototxt[16];
19330949fd4SBrian Somers   struct protoent *pe;
19430949fd4SBrian Somers   struct ncpaddr srcaddr, dstaddr;
19530949fd4SBrian Somers   const char *payload;		/* IP payload */
19630949fd4SBrian Somers   int datalen;			/* IP datagram length */
197af57ed9fSAtsushi Murai 
198cad7e742SBrian Somers   if (fp->f_action == A_NONE)
1990a4b6c5cSBrian Somers     return 0;		/* No rule is given. Permit this packet */
200cad7e742SBrian Somers 
20130949fd4SBrian Somers #ifndef NOINET6
20230949fd4SBrian Somers   if (family == AF_INET6) {
20330949fd4SBrian Somers     const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
20430949fd4SBrian Somers 
20530949fd4SBrian Somers     ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
20630949fd4SBrian Somers     ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
2076de54bbeSBrian Somers     datalen = ntohs(pip6->ip6_plen);
2086de54bbeSBrian Somers     payload = packet + sizeof *pip6;
20930949fd4SBrian Somers     cproto = pip6->ip6_nxt;
21030949fd4SBrian Somers   } else
21130949fd4SBrian Somers #endif
21230949fd4SBrian Somers   {
2130a4b6c5cSBrian Somers     /*
2140a4b6c5cSBrian Somers      * Deny any packet fragment that tries to over-write the header.
215cad7e742SBrian Somers      * Since we no longer have the real header available, punt on the
216cad7e742SBrian Somers      * largest normal header - 20 bytes for TCP without options, rounded
217cad7e742SBrian Somers      * up to the next possible fragment boundary.  Since the smallest
218cad7e742SBrian Somers      * `legal' MTU is 576, and the smallest recommended MTU is 296, any
2190a4b6c5cSBrian Somers      * fragmentation within this range is dubious at best
2200a4b6c5cSBrian Somers      */
22130949fd4SBrian Somers     const struct ip *pip = (const struct ip *)packet;
22230949fd4SBrian Somers 
223cad7e742SBrian Somers     len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
224cad7e742SBrian Somers     if (len > 0) {		/* Not first fragment within datagram */
22506a43ce0SBrian Somers       if (len < (24 >> 3)) {	/* don't allow fragment to over-write header */
22606a43ce0SBrian Somers         log_Printf(LogFILTER, " error: illegal header\n");
2270a4b6c5cSBrian Somers         return 1;
22806a43ce0SBrian Somers       }
229cad7e742SBrian Somers       /* permit fragments on in and out filter */
23006a43ce0SBrian Somers       if (!filter->fragok) {
23106a43ce0SBrian Somers         log_Printf(LogFILTER, " error: illegal fragmentation\n");
23206a43ce0SBrian Somers         return 1;
23306a43ce0SBrian Somers       } else
23406a43ce0SBrian Somers         return 0;
235cad7e742SBrian Somers     }
236cad7e742SBrian Somers 
23730949fd4SBrian Somers     ncpaddr_setip4(&srcaddr, pip->ip_src);
23830949fd4SBrian Somers     ncpaddr_setip4(&dstaddr, pip->ip_dst);
23930949fd4SBrian Somers     datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
24030949fd4SBrian Somers     payload = packet + (pip->ip_hl << 2);
24130949fd4SBrian Somers     cproto = pip->ip_p;
24230949fd4SBrian Somers   }
24330949fd4SBrian Somers 
24430949fd4SBrian Somers   if ((pe = getprotobynumber(cproto)) == NULL)
24530949fd4SBrian Somers     snprintf(prototxt, sizeof prototxt, "%d", cproto);
24630949fd4SBrian Somers   else
24730949fd4SBrian Somers     snprintf(prototxt, sizeof prototxt, "%s", pe->p_name);
24830949fd4SBrian Somers   gotinfo = estab = syn = finrst = didname = 0;
249af57ed9fSAtsushi Murai   sport = dport = 0;
25030949fd4SBrian Somers 
251cad7e742SBrian Somers   for (n = 0; n < MAXFILTERS; ) {
252cad7e742SBrian Somers     if (fp->f_action == A_NONE) {
253cad7e742SBrian Somers       n++;
254cad7e742SBrian Somers       fp++;
255cad7e742SBrian Somers       continue;
256cad7e742SBrian Somers     }
2575ca5389aSBrian Somers 
258cad7e742SBrian Somers     if (!didname) {
259dd7e2610SBrian Somers       log_Printf(LogDEBUG, "%s filter:\n", filter->name);
2608390b576SBrian Somers       didname = 1;
261cad7e742SBrian Somers     }
2628390b576SBrian Somers 
263cad7e742SBrian Somers     match = 0;
26430949fd4SBrian Somers 
26530949fd4SBrian Somers     if ((ncprange_family(&fp->f_src) == AF_UNSPEC ||
26630949fd4SBrian Somers          ncprange_contains(&fp->f_src, &srcaddr)) &&
26730949fd4SBrian Somers         (ncprange_family(&fp->f_dst) == AF_UNSPEC ||
26830949fd4SBrian Somers          ncprange_contains(&fp->f_dst, &dstaddr))) {
26930949fd4SBrian Somers       if (fp->f_proto != 0) {
270af57ed9fSAtsushi Murai         if (!gotinfo) {
271cad7e742SBrian Somers           const struct tcphdr *th;
272cad7e742SBrian Somers           const struct udphdr *uh;
273cad7e742SBrian Somers           const struct icmp *ih;
27430949fd4SBrian Somers #ifndef NOINET6
27530949fd4SBrian Somers           const struct icmp6_hdr *ih6;
27630949fd4SBrian Somers #endif
27730949fd4SBrian Somers           mindata = 0;
27830949fd4SBrian Somers           sport = dport = 0;
27963f98b41SBrian Somers           estab = syn = finrst = -1;
28030949fd4SBrian Somers 
28130949fd4SBrian Somers           switch (cproto) {
28230949fd4SBrian Somers           case IPPROTO_ICMP:
28330949fd4SBrian Somers             mindata = 8;	/* ICMP must be at least 8 octets */
28430949fd4SBrian Somers             ih = (const struct icmp *)payload;
28530949fd4SBrian Somers             sport = ntohs(ih->icmp_type);
286dd7e2610SBrian Somers             if (log_IsKept(LogDEBUG))
2878390b576SBrian Somers               snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
288af57ed9fSAtsushi Murai             break;
28930949fd4SBrian Somers 
29030949fd4SBrian Somers #ifndef NOINET6
29130949fd4SBrian Somers           case IPPROTO_ICMPV6:
29230949fd4SBrian Somers             mindata = 8;	/* ICMP must be at least 8 octets */
29330949fd4SBrian Somers             ih6 = (const struct icmp6_hdr *)payload;
29430949fd4SBrian Somers             sport = ntohs(ih6->icmp6_type);
29530949fd4SBrian Somers             if (log_IsKept(LogDEBUG))
29630949fd4SBrian Somers               snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
2971f9e5fe5SBrian Somers             break;
29830949fd4SBrian Somers #endif
29930949fd4SBrian Somers 
30030949fd4SBrian Somers           case IPPROTO_IGMP:
30130949fd4SBrian Somers             mindata = 8;	/* IGMP uses 8-octet messages */
30230949fd4SBrian Somers             break;
30330949fd4SBrian Somers 
30428149effSBrian Somers #ifdef IPPROTO_GRE
30528149effSBrian Somers           case IPPROTO_GRE:
30630949fd4SBrian Somers             mindata = 2;	/* GRE uses 2-octet+ messages */
30728149effSBrian Somers             break;
30828149effSBrian Somers #endif
30962e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
3102faae814SBrian Somers           case IPPROTO_OSPFIGP:
31130949fd4SBrian Somers             mindata = 8;	/* IGMP uses 8-octet messages */
3122faae814SBrian Somers             break;
31362e85934SBrian Somers #endif
31430949fd4SBrian Somers #ifndef NOINET6
31530949fd4SBrian Somers           case IPPROTO_IPV6:
31630949fd4SBrian Somers             mindata = 20;	/* RFC2893 Section 3.5: 5 * 32bit words */
3172231246bSBrian Somers             break;
31830949fd4SBrian Somers #endif
31906a43ce0SBrian Somers 
32030949fd4SBrian Somers           case IPPROTO_UDP:
32130949fd4SBrian Somers             mindata = 8;	/* UDP header is 8 octets */
32230949fd4SBrian Somers             uh = (const struct udphdr *)payload;
323944f7098SBrian Somers             sport = ntohs(uh->uh_sport);
324944f7098SBrian Somers             dport = ntohs(uh->uh_dport);
325dd7e2610SBrian Somers             if (log_IsKept(LogDEBUG))
3268390b576SBrian Somers               snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
3278390b576SBrian Somers                        sport, dport);
328af57ed9fSAtsushi Murai             break;
32930949fd4SBrian Somers 
330af57ed9fSAtsushi Murai           case IPPROTO_TCP:
33130949fd4SBrian Somers             th = (const struct tcphdr *)payload;
33230949fd4SBrian Somers             /*
33330949fd4SBrian Somers              * TCP headers are variable length.  The following code
334cad7e742SBrian Somers              * ensures that the TCP header length isn't de-referenced if
335cad7e742SBrian Somers              * the datagram is too short
336cad7e742SBrian Somers              */
33706a43ce0SBrian Somers             if (datalen < 20 || datalen < (th->th_off << 2)) {
33806a43ce0SBrian Somers               log_Printf(LogFILTER, " error: TCP header incorrect\n");
3390a4b6c5cSBrian Somers               return 1;
34006a43ce0SBrian Somers             }
341944f7098SBrian Somers             sport = ntohs(th->th_sport);
342944f7098SBrian Somers             dport = ntohs(th->th_dport);
343af57ed9fSAtsushi Murai             estab = (th->th_flags & TH_ACK);
34463f98b41SBrian Somers             syn = (th->th_flags & TH_SYN);
34563f98b41SBrian Somers             finrst = (th->th_flags & (TH_FIN|TH_RST));
3462b81c773SBrian Somers             if (log_IsKept(LogDEBUG)) {
3472b81c773SBrian Somers               if (!estab)
3488390b576SBrian Somers                 snprintf(dbuff, sizeof dbuff,
3498390b576SBrian Somers                          "flags = %02x, sport = %d, dport = %d",
350927145beSBrian Somers                          th->th_flags, sport, dport);
3512b81c773SBrian Somers               else
3522b81c773SBrian Somers                 *dbuff = '\0';
3532b81c773SBrian Somers             }
354af57ed9fSAtsushi Murai             break;
355af57ed9fSAtsushi Murai           default:
35630949fd4SBrian Somers             break;
35730949fd4SBrian Somers           }
35830949fd4SBrian Somers 
35930949fd4SBrian Somers           if (datalen < mindata) {
36030949fd4SBrian Somers             log_Printf(LogFILTER, " error: proto %s must be at least"
36130949fd4SBrian Somers                        " %d octets\n", prototxt, mindata);
36230949fd4SBrian Somers             return 1;
363af57ed9fSAtsushi Murai           }
364cad7e742SBrian Somers 
365dd7e2610SBrian Somers           if (log_IsKept(LogDEBUG)) {
3668390b576SBrian Somers             if (estab != -1) {
3678390b576SBrian Somers               len = strlen(dbuff);
36863f98b41SBrian Somers               snprintf(dbuff + len, sizeof dbuff - len,
36963f98b41SBrian Somers                        ", estab = %d, syn = %d, finrst = %d",
37063f98b41SBrian Somers                        estab, syn, finrst);
371af57ed9fSAtsushi Murai             }
37230949fd4SBrian Somers             log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", prototxt, dbuff);
3738390b576SBrian Somers           }
3748390b576SBrian Somers           gotinfo = 1;
3758390b576SBrian Somers         }
37630949fd4SBrian Somers 
377dd7e2610SBrian Somers         if (log_IsKept(LogDEBUG)) {
378cad7e742SBrian Somers           if (fp->f_srcop != OP_NONE) {
3798390b576SBrian Somers             snprintf(dbuff, sizeof dbuff, ", src %s %d",
380cad7e742SBrian Somers                      filter_Op2Nam(fp->f_srcop), fp->f_srcport);
3818390b576SBrian Somers             len = strlen(dbuff);
3828390b576SBrian Somers           } else
3838390b576SBrian Somers             len = 0;
384cad7e742SBrian Somers           if (fp->f_dstop != OP_NONE) {
3858390b576SBrian Somers             snprintf(dbuff + len, sizeof dbuff - len,
386cad7e742SBrian Somers                      ", dst %s %d", filter_Op2Nam(fp->f_dstop),
387cad7e742SBrian Somers                      fp->f_dstport);
3888390b576SBrian Somers           } else if (!len)
3898390b576SBrian Somers             *dbuff = '\0';
3908390b576SBrian Somers 
391dd7e2610SBrian Somers           log_Printf(LogDEBUG, "  rule = %d: Address match, "
39230949fd4SBrian Somers                      "check against proto %d%s, action = %s\n",
39330949fd4SBrian Somers                      n, fp->f_proto, dbuff, filter_Action2Nam(fp->f_action));
3948390b576SBrian Somers         }
395927145beSBrian Somers 
396cad7e742SBrian Somers         if (cproto == fp->f_proto) {
397cad7e742SBrian Somers           if ((fp->f_srcop == OP_NONE ||
398cad7e742SBrian Somers                PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
399cad7e742SBrian Somers               (fp->f_dstop == OP_NONE ||
400cad7e742SBrian Somers                PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
401cad7e742SBrian Somers               (fp->f_estab == 0 || estab) &&
402cad7e742SBrian Somers               (fp->f_syn == 0 || syn) &&
403cad7e742SBrian Somers               (fp->f_finrst == 0 || finrst)) {
404cad7e742SBrian Somers             match = 1;
405af57ed9fSAtsushi Murai           }
406af57ed9fSAtsushi Murai         }
407af57ed9fSAtsushi Murai       } else {
408cad7e742SBrian Somers         /* Address is matched and no protocol specified. Make a decision. */
409dd7e2610SBrian Somers         log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
410cad7e742SBrian Somers                    filter_Action2Nam(fp->f_action));
411cad7e742SBrian Somers         match = 1;
412af57ed9fSAtsushi Murai       }
4138390b576SBrian Somers     } else
414dd7e2610SBrian Somers       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
415cad7e742SBrian Somers 
416cad7e742SBrian Somers     if (match != fp->f_invert) {
417cad7e742SBrian Somers       /* Take specified action */
418cad7e742SBrian Somers       if (fp->f_action < A_NONE)
419cad7e742SBrian Somers         fp = &filter->rule[n = fp->f_action];
42006a43ce0SBrian Somers       else {
4210a4b6c5cSBrian Somers         if (fp->f_action == A_PERMIT) {
4220a4b6c5cSBrian Somers           if (psecs != NULL)
4230a4b6c5cSBrian Somers             *psecs = fp->timeout;
42406a43ce0SBrian Somers           if (strcmp(filter->name, "DIAL") == 0) {
42506a43ce0SBrian Somers             /* If dial filter then even print out accept packets */
42606a43ce0SBrian Somers             if (log_IsKept(LogFILTER)) {
42730949fd4SBrian Somers               snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
42806a43ce0SBrian Somers               log_Printf(LogFILTER, "%sbound rule = %d accept %s "
42930949fd4SBrian Somers                          "src = %s:%d dst = %s:%d\n", filter->name, n, prototxt,
43030949fd4SBrian Somers                          ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
43106a43ce0SBrian Somers             }
43206a43ce0SBrian Somers           }
4330a4b6c5cSBrian Somers           return 0;
43406a43ce0SBrian Somers         } else {
43506a43ce0SBrian Somers           if (log_IsKept(LogFILTER)) {
43630949fd4SBrian Somers             snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
43706a43ce0SBrian Somers             log_Printf(LogFILTER,
43806a43ce0SBrian Somers                        "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
43930949fd4SBrian Somers                        filter->name, n, prototxt,
44030949fd4SBrian Somers                        ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
44106a43ce0SBrian Somers           }
4420a4b6c5cSBrian Somers           return 1;
44330949fd4SBrian Somers         }		/* Explict match.  Deny this packet */
44406a43ce0SBrian Somers       }
445cad7e742SBrian Somers     } else {
446cad7e742SBrian Somers       n++;
447af57ed9fSAtsushi Murai       fp++;
448af57ed9fSAtsushi Murai     }
449af57ed9fSAtsushi Murai   }
45006a43ce0SBrian Somers 
45106a43ce0SBrian Somers   if (log_IsKept(LogFILTER)) {
45230949fd4SBrian Somers     snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
45306a43ce0SBrian Somers     log_Printf(LogFILTER,
45406a43ce0SBrian Somers                "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
45530949fd4SBrian Somers                filter->name, prototxt, ncpaddr_ntoa(&srcaddr), sport,
45630949fd4SBrian Somers                dstip, dport);
45706a43ce0SBrian Somers   }
45806a43ce0SBrian Somers 
45930949fd4SBrian Somers   return 1;		/* No rule matched, deny this packet */
460af57ed9fSAtsushi Murai }
461af57ed9fSAtsushi Murai 
46252c9ca19SBrian Somers static void
46352c9ca19SBrian Somers ip_LogDNS(const struct udphdr *uh, const char *direction)
46452c9ca19SBrian Somers {
46552c9ca19SBrian Somers   struct dns_header header;
46652c9ca19SBrian Somers   const u_short *pktptr;
46752c9ca19SBrian Somers   const u_char *ptr;
46847fe010cSBrian Somers   u_short *hptr, tmp;
46952c9ca19SBrian Somers   int len;
47052c9ca19SBrian Somers 
47152c9ca19SBrian Somers   ptr = (const char *)uh + sizeof *uh;
47252c9ca19SBrian Somers   len = ntohs(uh->uh_ulen) - sizeof *uh;
47352c9ca19SBrian Somers   if (len < sizeof header + 5)		/* rfc1024 */
47452c9ca19SBrian Somers     return;
47552c9ca19SBrian Somers 
47652c9ca19SBrian Somers   pktptr = (const u_short *)ptr;
47752c9ca19SBrian Somers   hptr = (u_short *)&header;
47852c9ca19SBrian Somers   ptr += sizeof header;
47952c9ca19SBrian Somers   len -= sizeof header;
48052c9ca19SBrian Somers 
48152c9ca19SBrian Somers   while (pktptr < (const u_short *)ptr) {
48252c9ca19SBrian Somers     *hptr++ = ntohs(*pktptr);		/* Careful of macro side-effects ! */
48352c9ca19SBrian Somers     pktptr++;
48452c9ca19SBrian Somers   }
48552c9ca19SBrian Somers 
48652c9ca19SBrian Somers   if (header.opcode == OPCODE_QUERY && header.qr == 0) {
48752c9ca19SBrian Somers     /* rfc1035 */
48826e6a622SBrian Somers     char namewithdot[MAXHOSTNAMELEN + 1], *n;
48952c9ca19SBrian Somers     const char *qtype, *qclass;
49052c9ca19SBrian Somers     const u_char *end;
49152c9ca19SBrian Somers 
49226e6a622SBrian Somers     n = namewithdot;
49352c9ca19SBrian Somers     end = ptr + len - 4;
49426e6a622SBrian Somers     if (end - ptr >= sizeof namewithdot)
49526e6a622SBrian Somers       end = ptr + sizeof namewithdot - 1;
49652c9ca19SBrian Somers     while (ptr < end) {
49752c9ca19SBrian Somers       len = *ptr++;
49852c9ca19SBrian Somers       if (len > end - ptr)
49952c9ca19SBrian Somers         len = end - ptr;
50026e6a622SBrian Somers       if (n != namewithdot)
50152c9ca19SBrian Somers         *n++ = '.';
50252c9ca19SBrian Somers       memcpy(n, ptr, len);
50352c9ca19SBrian Somers       ptr += len;
50452c9ca19SBrian Somers       n += len;
50552c9ca19SBrian Somers     }
50652c9ca19SBrian Somers     *n = '\0';
50747fe010cSBrian Somers 
50847fe010cSBrian Somers     if (log_IsKept(LogDNS)) {
50947fe010cSBrian Somers       memcpy(&tmp, end, sizeof tmp);
51047fe010cSBrian Somers       qtype = dns_Qtype2Txt(ntohs(tmp));
51147fe010cSBrian Somers       memcpy(&tmp, end + 2, sizeof tmp);
51247fe010cSBrian Somers       qclass = dns_Qclass2Txt(ntohs(tmp));
51352c9ca19SBrian Somers 
51452c9ca19SBrian Somers       log_Printf(LogDNS, "%sbound query %s %s %s\n",
51526e6a622SBrian Somers                  direction, qclass, qtype, namewithdot);
51652c9ca19SBrian Somers     }
51752c9ca19SBrian Somers   }
51847fe010cSBrian Somers }
51952c9ca19SBrian Somers 
520af57ed9fSAtsushi Murai /*
52130949fd4SBrian Somers  * Check if the given packet matches the given filter.
52230949fd4SBrian Somers  * One of pip or pip6 must be set.
523af57ed9fSAtsushi Murai  */
524af57ed9fSAtsushi Murai int
52530949fd4SBrian Somers PacketCheck(struct bundle *bundle, u_int32_t family,
52630949fd4SBrian Somers             const unsigned char *packet, int nb, struct filter *filter,
52730949fd4SBrian Somers             const char *prefix, unsigned *psecs)
528af57ed9fSAtsushi Murai {
52952c9ca19SBrian Somers   static const char *const TcpFlags[] = {
53052c9ca19SBrian Somers     "FIN", "SYN", "RST", "PSH", "ACK", "URG"
53152c9ca19SBrian Somers   };
53230949fd4SBrian Somers   const struct tcphdr *th;
53330949fd4SBrian Somers   const struct udphdr *uh;
53430949fd4SBrian Somers   const struct icmp *icmph;
53530949fd4SBrian Somers #ifndef NOINET6
53630949fd4SBrian Somers   const struct icmp6_hdr *icmp6h;
53730949fd4SBrian Somers #endif
53830949fd4SBrian Somers   const unsigned char *payload;
53930949fd4SBrian Somers   struct ncpaddr srcaddr, dstaddr;
54030949fd4SBrian Somers   int cproto, mask, len, n, pri, logit, loglen, result;
541d93d3a9cSBrian Somers   char logbuf[200];
54230949fd4SBrian Somers   int datalen, frag;
54330949fd4SBrian Somers   u_char tos;
544af57ed9fSAtsushi Murai 
545b565321aSBrian Somers   logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
546b565321aSBrian Somers           (!filter || filter->logok);
54755a8cdeaSBrian Somers   loglen = 0;
54852c9ca19SBrian Somers   pri = 0;
549af57ed9fSAtsushi Murai 
55030949fd4SBrian Somers #ifndef NOINET6
55130949fd4SBrian Somers   if (family == AF_INET6) {
55230949fd4SBrian Somers     const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
55330949fd4SBrian Somers 
55430949fd4SBrian Somers     ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
55530949fd4SBrian Somers     ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
55630949fd4SBrian Somers     datalen = ntohs(pip6->ip6_plen);
55730949fd4SBrian Somers     payload = packet + sizeof *pip6;
55830949fd4SBrian Somers     cproto = pip6->ip6_nxt;
5596de54bbeSBrian Somers     tos = 0;					/* XXX: pip6->ip6_vfc >> 4 ? */
56030949fd4SBrian Somers     frag = 0;					/* XXX: ??? */
56130949fd4SBrian Somers   } else
56230949fd4SBrian Somers #endif
56330949fd4SBrian Somers   {
56430949fd4SBrian Somers     const struct ip *pip = (const struct ip *)packet;
56530949fd4SBrian Somers 
56630949fd4SBrian Somers     ncpaddr_setip4(&srcaddr, pip->ip_src);
56730949fd4SBrian Somers     ncpaddr_setip4(&dstaddr, pip->ip_dst);
56830949fd4SBrian Somers     datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
56930949fd4SBrian Somers     payload = packet + (pip->ip_hl << 2);
57030949fd4SBrian Somers     cproto = pip->ip_p;
57130949fd4SBrian Somers     tos = pip->ip_tos;
57230949fd4SBrian Somers     frag = ntohs(pip->ip_off) & IP_OFFMASK;
57330949fd4SBrian Somers   }
57430949fd4SBrian Somers 
57552c9ca19SBrian Somers   uh = NULL;
576af57ed9fSAtsushi Murai 
57755a8cdeaSBrian Somers   if (logit && loglen < sizeof logbuf) {
57898251667SBrian Somers     if (prefix)
57998251667SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix);
58098251667SBrian Somers     else if (filter)
5815ca5389aSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
582b565321aSBrian Somers     else
583b565321aSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
58455a8cdeaSBrian Somers     loglen += strlen(logbuf + loglen);
58555a8cdeaSBrian Somers   }
586af57ed9fSAtsushi Murai 
58730949fd4SBrian Somers   switch (cproto) {
588af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
58955a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
59030949fd4SBrian Somers       len = datalen - sizeof *icmph;
59130949fd4SBrian Somers       icmph = (const struct icmp *)payload;
59255a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
59330949fd4SBrian Somers                "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmph->icmp_type);
59455a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
59555a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
59630949fd4SBrian Somers                "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
59755a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
598af57ed9fSAtsushi Murai     }
599af57ed9fSAtsushi Murai     break;
600da477886SBrian Somers 
60130949fd4SBrian Somers #ifndef NOINET6
60230949fd4SBrian Somers   case IPPROTO_ICMPV6:
60330949fd4SBrian Somers     if (logit && loglen < sizeof logbuf) {
60430949fd4SBrian Somers       len = datalen - sizeof *icmp6h;
60530949fd4SBrian Somers       icmp6h = (const struct icmp6_hdr *)payload;
60630949fd4SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
60730949fd4SBrian Somers                "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmp6h->icmp6_type);
60830949fd4SBrian Somers       loglen += strlen(logbuf + loglen);
60930949fd4SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
61030949fd4SBrian Somers                "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
61130949fd4SBrian Somers       loglen += strlen(logbuf + loglen);
61230949fd4SBrian Somers     }
61330949fd4SBrian Somers     break;
61430949fd4SBrian Somers #endif
61530949fd4SBrian Somers 
616af57ed9fSAtsushi Murai   case IPPROTO_UDP:
61730949fd4SBrian Somers     uh = (const struct udphdr *)payload;
61830949fd4SBrian Somers     if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
619da477886SBrian Somers       pri++;
620da477886SBrian Somers 
62130949fd4SBrian Somers     if (!frag && ncp_IsUrgentUdpPort(&bundle->ncp, ntohs(uh->uh_sport),
622da477886SBrian Somers                                      ntohs(uh->uh_dport)))
623da477886SBrian Somers       pri++;
624da477886SBrian Somers 
625da477886SBrian Somers     if (logit && loglen < sizeof logbuf) {
62630949fd4SBrian Somers       len = datalen - sizeof *uh;
62755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
62830949fd4SBrian Somers                "UDP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport));
62955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
63055a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
63130949fd4SBrian Somers                "%s:%d (%d/%d)", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport),
63298251667SBrian Somers                len, nb);
63355a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
634af57ed9fSAtsushi Murai     }
63598251667SBrian Somers 
63698251667SBrian Somers     if (Enabled(bundle, OPT_FILTERDECAP) &&
63730949fd4SBrian Somers         payload[sizeof *uh] == HDLC_ADDR &&
63830949fd4SBrian Somers         payload[sizeof *uh + 1] == HDLC_UI) {
63998251667SBrian Somers       u_short proto;
64098251667SBrian Somers       const char *type;
64198251667SBrian Somers 
64230949fd4SBrian Somers       memcpy(&proto, payload + sizeof *uh + 2, sizeof proto);
64398251667SBrian Somers       type = NULL;
64498251667SBrian Somers 
64598251667SBrian Somers       switch (ntohs(proto)) {
64698251667SBrian Somers         case PROTO_IP:
64798251667SBrian Somers           snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
64830949fd4SBrian Somers           result = PacketCheck(bundle, AF_INET, payload + sizeof *uh + 4,
64930949fd4SBrian Somers                                nb - (payload - packet) - sizeof *uh - 4, filter,
6500a4b6c5cSBrian Somers                                logbuf, psecs);
65198251667SBrian Somers           if (result != -2)
65298251667SBrian Somers               return result;
65398251667SBrian Somers           type = "IP";
65498251667SBrian Somers           break;
65598251667SBrian Somers 
65698251667SBrian Somers         case PROTO_VJUNCOMP: type = "compressed VJ";   break;
65798251667SBrian Somers         case PROTO_VJCOMP:   type = "uncompressed VJ"; break;
65898251667SBrian Somers         case PROTO_MP:       type = "Multi-link"; break;
65998251667SBrian Somers         case PROTO_ICOMPD:   type = "Individual link CCP"; break;
66098251667SBrian Somers         case PROTO_COMPD:    type = "CCP"; break;
66198251667SBrian Somers         case PROTO_IPCP:     type = "IPCP"; break;
66298251667SBrian Somers         case PROTO_LCP:      type = "LCP"; break;
66398251667SBrian Somers         case PROTO_PAP:      type = "PAP"; break;
66498251667SBrian Somers         case PROTO_CBCP:     type = "CBCP"; break;
66598251667SBrian Somers         case PROTO_LQR:      type = "LQR"; break;
66698251667SBrian Somers         case PROTO_CHAP:     type = "CHAP"; break;
66798251667SBrian Somers       }
66898251667SBrian Somers       if (type) {
66998251667SBrian Somers         snprintf(logbuf + loglen, sizeof logbuf - loglen,
67098251667SBrian Somers                  " - %s data", type);
67198251667SBrian Somers         loglen += strlen(logbuf + loglen);
67298251667SBrian Somers       }
67398251667SBrian Somers     }
67498251667SBrian Somers 
675af57ed9fSAtsushi Murai     break;
676da477886SBrian Somers 
67728149effSBrian Somers #ifdef IPPROTO_GRE
67828149effSBrian Somers   case IPPROTO_GRE:
67928149effSBrian Somers     if (logit && loglen < sizeof logbuf) {
68028149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
68130949fd4SBrian Somers           "GRE: %s ---> ", ncpaddr_ntoa(&srcaddr));
68228149effSBrian Somers       loglen += strlen(logbuf + loglen);
68328149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
68430949fd4SBrian Somers               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
68528149effSBrian Somers       loglen += strlen(logbuf + loglen);
68628149effSBrian Somers     }
68728149effSBrian Somers     break;
68828149effSBrian Somers #endif
68928149effSBrian Somers 
69062e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
6912faae814SBrian Somers   case IPPROTO_OSPFIGP:
6922faae814SBrian Somers     if (logit && loglen < sizeof logbuf) {
6932faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
69430949fd4SBrian Somers                "OSPF: %s ---> ", ncpaddr_ntoa(&srcaddr));
6952faae814SBrian Somers       loglen += strlen(logbuf + loglen);
6962faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
69730949fd4SBrian Somers                "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
6982faae814SBrian Somers       loglen += strlen(logbuf + loglen);
6992faae814SBrian Somers     }
7002faae814SBrian Somers     break;
70162e85934SBrian Somers #endif
702da477886SBrian Somers 
70330949fd4SBrian Somers #ifndef NOINET6
70430949fd4SBrian Somers   case IPPROTO_IPV6:
70530949fd4SBrian Somers     if (logit && loglen < sizeof logbuf) {
70630949fd4SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
70730949fd4SBrian Somers                "IPv6: %s ---> ", ncpaddr_ntoa(&srcaddr));
70830949fd4SBrian Somers       loglen += strlen(logbuf + loglen);
70930949fd4SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
71030949fd4SBrian Somers                "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
71130949fd4SBrian Somers       loglen += strlen(logbuf + loglen);
71230949fd4SBrian Somers     }
71330949fd4SBrian Somers 
71430949fd4SBrian Somers     if (Enabled(bundle, OPT_FILTERDECAP)) {
71530949fd4SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
71630949fd4SBrian Somers       result = PacketCheck(bundle, AF_INET6, payload, nb - (payload - packet),
71730949fd4SBrian Somers                            filter, logbuf, psecs);
71830949fd4SBrian Somers       if (result != -2)
71930949fd4SBrian Somers         return result;
72030949fd4SBrian Somers     }
72130949fd4SBrian Somers     break;
72230949fd4SBrian Somers #endif
72330949fd4SBrian Somers 
724eee772ecSBrian Somers   case IPPROTO_IPIP:
725eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
726eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
72730949fd4SBrian Somers                "IPIP: %s ---> ", ncpaddr_ntoa(&srcaddr));
728eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
729eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
73030949fd4SBrian Somers                "%s", ncpaddr_ntoa(&dstaddr));
731eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
73230949fd4SBrian Somers     }
733da70ad60SBrian Somers 
73430949fd4SBrian Somers     if (Enabled(bundle, OPT_FILTERDECAP) &&
73530949fd4SBrian Somers         ((const struct ip *)payload)->ip_v == 4) {
736da70ad60SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
73730949fd4SBrian Somers       result = PacketCheck(bundle, AF_INET, payload, nb - (payload - packet),
73830949fd4SBrian Somers                            filter, logbuf, psecs);
739da70ad60SBrian Somers       if (result != -2)
740da70ad60SBrian Somers         return result;
741da70ad60SBrian Somers     }
742eee772ecSBrian Somers     break;
743da477886SBrian Somers 
7442231246bSBrian Somers   case IPPROTO_ESP:
7452231246bSBrian Somers     if (logit && loglen < sizeof logbuf) {
7462231246bSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
74730949fd4SBrian Somers                "ESP: %s ---> ", ncpaddr_ntoa(&srcaddr));
7482231246bSBrian Somers       loglen += strlen(logbuf + loglen);
74925254215SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
75030949fd4SBrian Somers                ncpaddr_ntoa(&dstaddr), payload);
7512231246bSBrian Somers       loglen += strlen(logbuf + loglen);
7522231246bSBrian Somers     }
7532231246bSBrian Somers     break;
7542231246bSBrian Somers 
7552231246bSBrian Somers   case IPPROTO_AH:
7562231246bSBrian Somers     if (logit && loglen < sizeof logbuf) {
7572231246bSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
75830949fd4SBrian Somers                "AH: %s ---> ", ncpaddr_ntoa(&srcaddr));
7592231246bSBrian Somers       loglen += strlen(logbuf + loglen);
76025254215SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
76130949fd4SBrian Somers                ncpaddr_ntoa(&dstaddr), payload + sizeof(u_int32_t));
7622231246bSBrian Somers       loglen += strlen(logbuf + loglen);
7632231246bSBrian Somers     }
7642231246bSBrian Somers     break;
7652231246bSBrian Somers 
766eee772ecSBrian Somers   case IPPROTO_IGMP:
767eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
76830949fd4SBrian Somers       uh = (const struct udphdr *)payload;
769eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
77030949fd4SBrian Somers                "IGMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr),
7710a4b6c5cSBrian Somers                ntohs(uh->uh_sport));
772eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
773eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
77430949fd4SBrian Somers                "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport));
775eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
776eee772ecSBrian Somers     }
777eee772ecSBrian Somers     break;
778da477886SBrian Somers 
779af57ed9fSAtsushi Murai   case IPPROTO_TCP:
78030949fd4SBrian Somers     th = (const struct tcphdr *)payload;
78130949fd4SBrian Somers     if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
782442f8495SBrian Somers       pri++;
783da477886SBrian Somers 
78430949fd4SBrian Somers     if (!frag && ncp_IsUrgentTcpPort(&bundle->ncp, ntohs(th->th_sport),
785442f8495SBrian Somers                                      ntohs(th->th_dport)))
786442f8495SBrian Somers       pri++;
787442f8495SBrian Somers 
78855a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
78930949fd4SBrian Somers       len = datalen - (th->th_off << 2);
79055a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
79130949fd4SBrian Somers            "TCP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(th->th_sport));
79255a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
79355a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
79430949fd4SBrian Somers                "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(th->th_dport));
79555a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
796af57ed9fSAtsushi Murai       n = 0;
797af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
79855a8cdeaSBrian Somers         if (th->th_flags & mask) {
79955a8cdeaSBrian Somers           snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
80055a8cdeaSBrian Somers           loglen += strlen(logbuf + loglen);
80155a8cdeaSBrian Somers         }
802af57ed9fSAtsushi Murai         n++;
803af57ed9fSAtsushi Murai       }
80455a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
8053a2e4f62SBrian Somers                "  seq:%lx  ack:%lx (%d/%d)",
8063a2e4f62SBrian Somers                (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
80755a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
808af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
80930949fd4SBrian Somers         const u_short *sp;
810af57ed9fSAtsushi Murai 
81130949fd4SBrian Somers         sp = (const u_short *)(payload + 20);
81255a8cdeaSBrian Somers         if (ntohs(sp[0]) == 0x0204) {
81355a8cdeaSBrian Somers           snprintf(logbuf + loglen, sizeof logbuf - loglen,
81455a8cdeaSBrian Somers                    " MSS = %d", ntohs(sp[1]));
81555a8cdeaSBrian Somers           loglen += strlen(logbuf + loglen);
81655a8cdeaSBrian Somers         }
817af57ed9fSAtsushi Murai       }
818af57ed9fSAtsushi Murai     }
819af57ed9fSAtsushi Murai     break;
82098251667SBrian Somers 
82198251667SBrian Somers   default:
82298251667SBrian Somers     if (prefix)
82398251667SBrian Somers       return -2;
82430949fd4SBrian Somers 
82530949fd4SBrian Somers     if (logit && loglen < sizeof logbuf) {
82630949fd4SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
82730949fd4SBrian Somers                "<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr));
82830949fd4SBrian Somers       loglen += strlen(logbuf + loglen);
82930949fd4SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
83030949fd4SBrian Somers                "%s (%d)", ncpaddr_ntoa(&dstaddr), nb);
83130949fd4SBrian Somers       loglen += strlen(logbuf + loglen);
83230949fd4SBrian Somers     }
83330949fd4SBrian Somers     break;
834af57ed9fSAtsushi Murai   }
83576bd0c0aSDoug Rabson 
83630949fd4SBrian Somers   if (filter && FilterCheck(packet, family, filter, psecs)) {
837710e9c29SBrian Somers     if (logit)
838dd7e2610SBrian Somers       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
83952c9ca19SBrian Somers     result = -1;
840af57ed9fSAtsushi Murai   } else {
8415ca5389aSBrian Somers     /* Check Keep Alive filter */
84252c9ca19SBrian Somers     if (logit && log_IsKept(LogTCPIP)) {
8430a4b6c5cSBrian Somers       unsigned alivesecs;
8440a4b6c5cSBrian Somers 
8450a4b6c5cSBrian Somers       alivesecs = 0;
84630949fd4SBrian Somers       if (filter &&
84730949fd4SBrian Somers           FilterCheck(packet, family, &bundle->filter.alive, &alivesecs))
848dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
8490a4b6c5cSBrian Somers       else if (psecs != NULL) {
8500a4b6c5cSBrian Somers         if(*psecs == 0)
8510a4b6c5cSBrian Somers           *psecs = alivesecs;
8520a4b6c5cSBrian Somers         if (*psecs) {
8530a4b6c5cSBrian Somers           if (*psecs != alivesecs)
8540a4b6c5cSBrian Somers             log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n",
8550a4b6c5cSBrian Somers                        logbuf, *psecs, alivesecs);
8561e991daaSBrian Somers           else
8570a4b6c5cSBrian Somers             log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs);
8580a4b6c5cSBrian Somers         } else
859dd7e2610SBrian Somers           log_Printf(LogTCPIP, "%s\n", logbuf);
86053c9f6c0SAtsushi Murai       }
8610a4b6c5cSBrian Somers     }
86252c9ca19SBrian Somers     result = pri;
863af57ed9fSAtsushi Murai   }
86452c9ca19SBrian Somers 
865b565321aSBrian Somers   if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
86652c9ca19SBrian Somers     ip_LogDNS(uh, filter->name);
86752c9ca19SBrian Somers 
86852c9ca19SBrian Somers   return result;
869af57ed9fSAtsushi Murai }
870af57ed9fSAtsushi Murai 
87130949fd4SBrian Somers static int
87230949fd4SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af)
8737a6f8720SBrian Somers {
874af57ed9fSAtsushi Murai   int nb, nw;
875b6e82f33SBrian Somers   struct tun_data tun;
8763a7b6d76SBrian Somers   char *data;
8770a4b6c5cSBrian Somers   unsigned secs, alivesecs;
8785d9e6103SBrian Somers 
87926af0ae9SBrian Somers   nb = m_length(bp);
88076d98538SBrian Somers   if (nb > sizeof tun.data) {
88176d98538SBrian Somers     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
88276d98538SBrian Somers                l->name, nb, (int)(sizeof tun.data));
88326af0ae9SBrian Somers     m_freem(bp);
88430949fd4SBrian Somers     return 0;
88576d98538SBrian Somers   }
8865d9e6103SBrian Somers   mbuf_Read(bp, tun.data, nb);
887af57ed9fSAtsushi Murai 
8880a4b6c5cSBrian Somers   secs = 0;
88930949fd4SBrian Somers   if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in,
89030949fd4SBrian Somers                   NULL, &secs) < 0)
89130949fd4SBrian Somers     return 0;
8926db75539SBrian Somers 
8930a4b6c5cSBrian Somers   alivesecs = 0;
89430949fd4SBrian Somers   if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) {
8950a4b6c5cSBrian Somers     if (secs == 0)
8960a4b6c5cSBrian Somers       secs = alivesecs;
8970a4b6c5cSBrian Somers     bundle_StartIdleTimer(bundle, secs);
8980a4b6c5cSBrian Somers   }
8991e991daaSBrian Somers 
9003a7b6d76SBrian Somers   if (bundle->dev.header) {
90130949fd4SBrian Somers     tun.header.family = htonl(af);
90270ee81ffSBrian Somers     nb += sizeof tun - sizeof tun.data;
9033a7b6d76SBrian Somers     data = (char *)&tun;
9043a7b6d76SBrian Somers   } else
9053a7b6d76SBrian Somers     data = tun.data;
9063a7b6d76SBrian Somers 
9073a7b6d76SBrian Somers   nw = write(bundle->dev.fd, data, nb);
908c4c4aaacSBrian Somers   if (nw != nb) {
90957fd05c4SBrian Somers     if (nw == -1)
91076d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
91176d98538SBrian Somers                  l->name, nb, strerror(errno));
91257fd05c4SBrian Somers     else
91376d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
9146db75539SBrian Somers   }
9155d9e6103SBrian Somers 
91630949fd4SBrian Somers   return nb;
91730949fd4SBrian Somers }
91830949fd4SBrian Somers 
91930949fd4SBrian Somers struct mbuf *
92030949fd4SBrian Somers ipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
92130949fd4SBrian Somers {
92230949fd4SBrian Somers   int nb;
92330949fd4SBrian Somers 
92430949fd4SBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
92530949fd4SBrian Somers     log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n");
92630949fd4SBrian Somers     m_freem(bp);
9275d9e6103SBrian Somers     return NULL;
928af57ed9fSAtsushi Murai   }
929af57ed9fSAtsushi Murai 
93030949fd4SBrian Somers   m_settype(bp, MB_IPIN);
93130949fd4SBrian Somers 
93230949fd4SBrian Somers   nb = ip_Input(bundle, l, bp, AF_INET);
93330949fd4SBrian Somers   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
93430949fd4SBrian Somers 
93530949fd4SBrian Somers   return NULL;
93630949fd4SBrian Somers }
93730949fd4SBrian Somers 
93830949fd4SBrian Somers #ifndef NOINET6
93930949fd4SBrian Somers struct mbuf *
94030949fd4SBrian Somers ipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
941af57ed9fSAtsushi Murai {
94230949fd4SBrian Somers   int nb;
943af57ed9fSAtsushi Murai 
9441136c6acSBrian Somers   if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) {
94530949fd4SBrian Somers     log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n");
94630949fd4SBrian Somers     m_freem(bp);
94730949fd4SBrian Somers     return NULL;
948af57ed9fSAtsushi Murai   }
949af57ed9fSAtsushi Murai 
95030949fd4SBrian Somers   m_settype(bp, MB_IPV6IN);
9516f8e9f0aSBrian Somers 
95230949fd4SBrian Somers   nb = ip_Input(bundle, l, bp, AF_INET6);
95330949fd4SBrian Somers   ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb);
95430949fd4SBrian Somers 
95530949fd4SBrian Somers   return NULL;
9566f8e9f0aSBrian Somers }
95730949fd4SBrian Somers #endif
958