165309e5cSBrian Somers /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
465309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
565309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
665309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ)
765309e5cSBrian Somers * All rights reserved.
8af57ed9fSAtsushi Murai *
965309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without
1065309e5cSBrian Somers * modification, are permitted provided that the following conditions
1165309e5cSBrian Somers * are met:
1265309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright
1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer.
1465309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
1565309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the
1665309e5cSBrian Somers * documentation and/or other materials provided with the distribution.
17af57ed9fSAtsushi Murai *
1865309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1965309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2065309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2165309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2265309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2365309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2465309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2565309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2665309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2765309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2865309e5cSBrian Somers * SUCH DAMAGE.
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>
431fa665f5SBrian Somers #include <sys/un.h>
4475240ed1SBrian Somers
4557fd05c4SBrian Somers #include <errno.h>
4630949fd4SBrian Somers #include <netdb.h>
4775240ed1SBrian Somers #include <stdio.h>
4875240ed1SBrian Somers #include <string.h>
495d9e6103SBrian Somers #include <termios.h>
5075240ed1SBrian Somers #include <unistd.h>
5175240ed1SBrian Somers
525d9e6103SBrian Somers #include "layer.h"
535d9e6103SBrian Somers #include "proto.h"
54927145beSBrian Somers #include "mbuf.h"
55927145beSBrian Somers #include "log.h"
5675240ed1SBrian Somers #include "defs.h"
5775240ed1SBrian Somers #include "timer.h"
5875240ed1SBrian Somers #include "fsm.h"
59879ed6faSBrian Somers #include "lqr.h"
6075240ed1SBrian Somers #include "hdlc.h"
615828db6dSBrian Somers #include "throughput.h"
625828db6dSBrian Somers #include "iplist.h"
63eaa4df37SBrian Somers #include "slcompress.h"
6430949fd4SBrian Somers #include "ncpaddr.h"
6530949fd4SBrian Somers #include "ip.h"
6675240ed1SBrian Somers #include "ipcp.h"
671ae349f5Scvs2svn #include "filter.h"
682f786681SBrian Somers #include "descriptor.h"
6975240ed1SBrian Somers #include "lcp.h"
703b0f8d2eSBrian Somers #include "ccp.h"
713b0f8d2eSBrian Somers #include "link.h"
723b0f8d2eSBrian Somers #include "mp.h"
73972a1bcfSBrian Somers #ifndef NORADIUS
74972a1bcfSBrian Somers #include "radius.h"
75972a1bcfSBrian Somers #endif
7630949fd4SBrian Somers #include "ipv6cp.h"
7730949fd4SBrian Somers #include "ncp.h"
787a6f8720SBrian Somers #include "bundle.h"
796a6b4bbbSBrian Somers #include "tun.h"
80af57ed9fSAtsushi Murai
8152c9ca19SBrian Somers
8252c9ca19SBrian Somers #define OPCODE_QUERY 0
8352c9ca19SBrian Somers #define OPCODE_IQUERY 1
8452c9ca19SBrian Somers #define OPCODE_STATUS 2
8552c9ca19SBrian Somers
8652c9ca19SBrian Somers struct dns_header {
8752c9ca19SBrian Somers u_short id;
8852c9ca19SBrian Somers unsigned qr : 1;
8952c9ca19SBrian Somers unsigned opcode : 4;
9052c9ca19SBrian Somers unsigned aa : 1;
9152c9ca19SBrian Somers unsigned tc : 1;
9252c9ca19SBrian Somers unsigned rd : 1;
9352c9ca19SBrian Somers unsigned ra : 1;
9452c9ca19SBrian Somers unsigned z : 3;
9552c9ca19SBrian Somers unsigned rcode : 4;
9652c9ca19SBrian Somers u_short qdcount;
9752c9ca19SBrian Somers u_short ancount;
9852c9ca19SBrian Somers u_short nscount;
9952c9ca19SBrian Somers u_short arcount;
100182c898aSBrian Somers };
101af57ed9fSAtsushi Murai
10252c9ca19SBrian Somers static const char *
dns_Qclass2Txt(u_short qclass)10352c9ca19SBrian Somers dns_Qclass2Txt(u_short qclass)
10452c9ca19SBrian Somers {
10552c9ca19SBrian Somers static char failure[6];
10652c9ca19SBrian Somers struct {
10752c9ca19SBrian Somers u_short id;
10852c9ca19SBrian Somers const char *txt;
10952c9ca19SBrian Somers } qtxt[] = {
11052c9ca19SBrian Somers /* rfc1035 */
11152c9ca19SBrian Somers { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
11252c9ca19SBrian Somers };
113057f1760SBrian Somers unsigned f;
11452c9ca19SBrian Somers
11552c9ca19SBrian Somers for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
11652c9ca19SBrian Somers if (qtxt[f].id == qclass)
11752c9ca19SBrian Somers return qtxt[f].txt;
11852c9ca19SBrian Somers
119d6d3eeabSBrian Somers return HexStr(qclass, failure, sizeof failure);
12052c9ca19SBrian Somers }
12152c9ca19SBrian Somers
12252c9ca19SBrian Somers static const char *
dns_Qtype2Txt(u_short qtype)12352c9ca19SBrian Somers dns_Qtype2Txt(u_short qtype)
12452c9ca19SBrian Somers {
12552c9ca19SBrian Somers static char failure[6];
12652c9ca19SBrian Somers struct {
12752c9ca19SBrian Somers u_short id;
12852c9ca19SBrian Somers const char *txt;
12952c9ca19SBrian Somers } qtxt[] = {
13052c9ca19SBrian Somers /* rfc1035/rfc1700 */
13152c9ca19SBrian Somers { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
13252c9ca19SBrian Somers { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
13352c9ca19SBrian Somers { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
13452c9ca19SBrian Somers { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
13552c9ca19SBrian Somers { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
13652c9ca19SBrian Somers { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
13752c9ca19SBrian Somers { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
13852c9ca19SBrian Somers { 254, "MAILA" }, { 255, "*" }
13952c9ca19SBrian Somers };
140057f1760SBrian Somers unsigned f;
14152c9ca19SBrian Somers
14252c9ca19SBrian Somers for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
14352c9ca19SBrian Somers if (qtxt[f].id == qtype)
14452c9ca19SBrian Somers return qtxt[f].txt;
14552c9ca19SBrian Somers
146d6d3eeabSBrian Somers return HexStr(qtype, failure, sizeof failure);
14752c9ca19SBrian Somers }
14852c9ca19SBrian Somers
149cad7e742SBrian Somers static __inline int
PortMatch(int op,u_short pport,u_short rport)150944f7098SBrian Somers PortMatch(int op, u_short pport, u_short rport)
151af57ed9fSAtsushi Murai {
152af57ed9fSAtsushi Murai switch (op) {
153af57ed9fSAtsushi Murai case OP_EQ:
1540a4b6c5cSBrian Somers return pport == rport;
155af57ed9fSAtsushi Murai case OP_GT:
1560a4b6c5cSBrian Somers return pport > rport;
157af57ed9fSAtsushi Murai case OP_LT:
1580a4b6c5cSBrian Somers return pport < rport;
159af57ed9fSAtsushi Murai default:
1600a4b6c5cSBrian Somers return 0;
161af57ed9fSAtsushi Murai }
162af57ed9fSAtsushi Murai }
163af57ed9fSAtsushi Murai
164af57ed9fSAtsushi Murai /*
165e2ccf799SDiomidis Spinellis * Return a text string representing the cproto protocol number.
166e2ccf799SDiomidis Spinellis *
167e2ccf799SDiomidis Spinellis * The purpose of this routine is calculate this result, for
168e2ccf799SDiomidis Spinellis * the many times it is needed in FilterCheck, only on demand
169e2ccf799SDiomidis Spinellis * (i.e. when the corresponding logging functions are invoked).
170e2ccf799SDiomidis Spinellis *
171e2ccf799SDiomidis Spinellis * This optimization saves, over the previous implementation, which
172e2ccf799SDiomidis Spinellis * calculated prototxt at the beginning of FilterCheck, an
173e2ccf799SDiomidis Spinellis * open/read/close system call sequence per packet, approximately
174e2ccf799SDiomidis Spinellis * halving the ppp system overhead and reducing the overall (u + s)
175e2ccf799SDiomidis Spinellis * time by 38%.
176e2ccf799SDiomidis Spinellis *
177e2ccf799SDiomidis Spinellis * The caching performed here is just a side effect.
178e2ccf799SDiomidis Spinellis */
179e2ccf799SDiomidis Spinellis static const char *
prototxt(int cproto)180e2ccf799SDiomidis Spinellis prototxt(int cproto)
181e2ccf799SDiomidis Spinellis {
182e2ccf799SDiomidis Spinellis static int oproto = -1;
183e2ccf799SDiomidis Spinellis static char protobuff[16] = "-1";
184e2ccf799SDiomidis Spinellis struct protoent *pe;
185e2ccf799SDiomidis Spinellis
186e2ccf799SDiomidis Spinellis if (cproto == oproto)
187e2ccf799SDiomidis Spinellis return protobuff;
188e2ccf799SDiomidis Spinellis if ((pe = getprotobynumber(cproto)) == NULL)
189e2ccf799SDiomidis Spinellis snprintf(protobuff, sizeof protobuff, "%d", cproto);
190e2ccf799SDiomidis Spinellis else
191e2ccf799SDiomidis Spinellis snprintf(protobuff, sizeof protobuff, "%s", pe->p_name);
192e2ccf799SDiomidis Spinellis oproto = cproto;
193e2ccf799SDiomidis Spinellis return (protobuff);
194e2ccf799SDiomidis Spinellis }
195e2ccf799SDiomidis Spinellis
196e2ccf799SDiomidis Spinellis /*
19730949fd4SBrian Somers * Check a packet against the given filter
19830949fd4SBrian Somers * Returns 0 to accept the packet, non-zero to drop the packet.
19930949fd4SBrian Somers * If psecs is not NULL, populate it with the timeout associated
20030949fd4SBrian Somers * with the filter rule matched.
201cad7e742SBrian Somers *
202cad7e742SBrian Somers * If filtering is enabled, the initial fragment of a datagram must
203cad7e742SBrian Somers * contain the complete protocol header, and subsequent fragments
204cad7e742SBrian Somers * must not attempt to over-write it.
20530949fd4SBrian Somers *
20630949fd4SBrian Somers * One (and only one) of pip or pip6 must be set.
207af57ed9fSAtsushi Murai */
20830949fd4SBrian Somers int
FilterCheck(const unsigned char * packet,u_int32_t family __unused,const struct filter * filter,unsigned * psecs)209f2f076a9SBrian Somers FilterCheck(const unsigned char *packet,
210f2f076a9SBrian Somers #ifdef NOINET6
211f2f076a9SBrian Somers u_int32_t family __unused,
212f2f076a9SBrian Somers #else
213f2f076a9SBrian Somers u_int32_t family,
214f2f076a9SBrian Somers #endif
21530949fd4SBrian Somers const struct filter *filter, unsigned *psecs)
216af57ed9fSAtsushi Murai {
217cad7e742SBrian Somers int gotinfo; /* true if IP payload decoded */
21830949fd4SBrian Somers int cproto; /* IPPROTO_* protocol number if (gotinfo) */
219cad7e742SBrian Somers int estab, syn, finrst; /* TCP state flags if (gotinfo) */
220cad7e742SBrian Somers u_short sport, dport; /* src, dest port from packet if (gotinfo) */
221cad7e742SBrian Somers int n; /* filter rule to process */
222cad7e742SBrian Somers int len; /* bytes used in dbuff */
223cad7e742SBrian Somers int didname; /* true if filter header printed */
224cad7e742SBrian Somers int match; /* true if condition matched */
22530949fd4SBrian Somers int mindata; /* minimum data size or zero */
226cad7e742SBrian Somers const struct filterent *fp = filter->rule;
2276cd3353bSEugene Grosbein char dbuff[100], dstip[NCP_ASCIIBUFFERSIZE];
22830949fd4SBrian Somers struct ncpaddr srcaddr, dstaddr;
22930949fd4SBrian Somers const char *payload; /* IP payload */
23030949fd4SBrian Somers int datalen; /* IP datagram length */
231af57ed9fSAtsushi Murai
232cad7e742SBrian Somers if (fp->f_action == A_NONE)
2330a4b6c5cSBrian Somers return 0; /* No rule is given. Permit this packet */
234cad7e742SBrian Somers
23530949fd4SBrian Somers #ifndef NOINET6
23630949fd4SBrian Somers if (family == AF_INET6) {
23730949fd4SBrian Somers const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
23830949fd4SBrian Somers
23930949fd4SBrian Somers ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
24030949fd4SBrian Somers ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
2416de54bbeSBrian Somers datalen = ntohs(pip6->ip6_plen);
2426de54bbeSBrian Somers payload = packet + sizeof *pip6;
24330949fd4SBrian Somers cproto = pip6->ip6_nxt;
24430949fd4SBrian Somers } else
24530949fd4SBrian Somers #endif
24630949fd4SBrian Somers {
2470a4b6c5cSBrian Somers /*
2480a4b6c5cSBrian Somers * Deny any packet fragment that tries to over-write the header.
249cad7e742SBrian Somers * Since we no longer have the real header available, punt on the
250cad7e742SBrian Somers * largest normal header - 20 bytes for TCP without options, rounded
251cad7e742SBrian Somers * up to the next possible fragment boundary. Since the smallest
252cad7e742SBrian Somers * `legal' MTU is 576, and the smallest recommended MTU is 296, any
2530a4b6c5cSBrian Somers * fragmentation within this range is dubious at best
2540a4b6c5cSBrian Somers */
25530949fd4SBrian Somers const struct ip *pip = (const struct ip *)packet;
25630949fd4SBrian Somers
257cad7e742SBrian Somers len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */
258cad7e742SBrian Somers if (len > 0) { /* Not first fragment within datagram */
25906a43ce0SBrian Somers if (len < (24 >> 3)) { /* don't allow fragment to over-write header */
26006a43ce0SBrian Somers log_Printf(LogFILTER, " error: illegal header\n");
2610a4b6c5cSBrian Somers return 1;
26206a43ce0SBrian Somers }
263cad7e742SBrian Somers /* permit fragments on in and out filter */
26406a43ce0SBrian Somers if (!filter->fragok) {
26506a43ce0SBrian Somers log_Printf(LogFILTER, " error: illegal fragmentation\n");
26606a43ce0SBrian Somers return 1;
26706a43ce0SBrian Somers } else
26806a43ce0SBrian Somers return 0;
269cad7e742SBrian Somers }
270cad7e742SBrian Somers
27130949fd4SBrian Somers ncpaddr_setip4(&srcaddr, pip->ip_src);
27230949fd4SBrian Somers ncpaddr_setip4(&dstaddr, pip->ip_dst);
27330949fd4SBrian Somers datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
27430949fd4SBrian Somers payload = packet + (pip->ip_hl << 2);
27530949fd4SBrian Somers cproto = pip->ip_p;
27630949fd4SBrian Somers }
27730949fd4SBrian Somers
278e2ccf799SDiomidis Spinellis
27930949fd4SBrian Somers gotinfo = estab = syn = finrst = didname = 0;
280af57ed9fSAtsushi Murai sport = dport = 0;
28130949fd4SBrian Somers
282cad7e742SBrian Somers for (n = 0; n < MAXFILTERS; ) {
283cad7e742SBrian Somers if (fp->f_action == A_NONE) {
284cad7e742SBrian Somers n++;
285cad7e742SBrian Somers fp++;
286cad7e742SBrian Somers continue;
287cad7e742SBrian Somers }
2885ca5389aSBrian Somers
289cad7e742SBrian Somers if (!didname) {
290dd7e2610SBrian Somers log_Printf(LogDEBUG, "%s filter:\n", filter->name);
2918390b576SBrian Somers didname = 1;
292cad7e742SBrian Somers }
2938390b576SBrian Somers
294cad7e742SBrian Somers match = 0;
29530949fd4SBrian Somers
29630949fd4SBrian Somers if ((ncprange_family(&fp->f_src) == AF_UNSPEC ||
29730949fd4SBrian Somers ncprange_contains(&fp->f_src, &srcaddr)) &&
29830949fd4SBrian Somers (ncprange_family(&fp->f_dst) == AF_UNSPEC ||
29930949fd4SBrian Somers ncprange_contains(&fp->f_dst, &dstaddr))) {
30030949fd4SBrian Somers if (fp->f_proto != 0) {
301af57ed9fSAtsushi Murai if (!gotinfo) {
302cad7e742SBrian Somers const struct tcphdr *th;
303cad7e742SBrian Somers const struct udphdr *uh;
304cad7e742SBrian Somers const struct icmp *ih;
30530949fd4SBrian Somers #ifndef NOINET6
30630949fd4SBrian Somers const struct icmp6_hdr *ih6;
30730949fd4SBrian Somers #endif
30830949fd4SBrian Somers mindata = 0;
30930949fd4SBrian Somers sport = dport = 0;
31063f98b41SBrian Somers estab = syn = finrst = -1;
31130949fd4SBrian Somers
31230949fd4SBrian Somers switch (cproto) {
31330949fd4SBrian Somers case IPPROTO_ICMP:
31430949fd4SBrian Somers mindata = 8; /* ICMP must be at least 8 octets */
31530949fd4SBrian Somers ih = (const struct icmp *)payload;
31692941b90SBrian Somers sport = ih->icmp_type;
317dd7e2610SBrian Somers if (log_IsKept(LogDEBUG))
3188390b576SBrian Somers snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
319af57ed9fSAtsushi Murai break;
32030949fd4SBrian Somers
32130949fd4SBrian Somers #ifndef NOINET6
32230949fd4SBrian Somers case IPPROTO_ICMPV6:
32330949fd4SBrian Somers mindata = 8; /* ICMP must be at least 8 octets */
32430949fd4SBrian Somers ih6 = (const struct icmp6_hdr *)payload;
32592941b90SBrian Somers sport = ih6->icmp6_type;
32630949fd4SBrian Somers if (log_IsKept(LogDEBUG))
32730949fd4SBrian Somers snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
3281f9e5fe5SBrian Somers break;
32930949fd4SBrian Somers #endif
33030949fd4SBrian Somers
33130949fd4SBrian Somers case IPPROTO_IGMP:
33230949fd4SBrian Somers mindata = 8; /* IGMP uses 8-octet messages */
33330949fd4SBrian Somers break;
33430949fd4SBrian Somers
33528149effSBrian Somers #ifdef IPPROTO_GRE
33628149effSBrian Somers case IPPROTO_GRE:
33730949fd4SBrian Somers mindata = 2; /* GRE uses 2-octet+ messages */
33828149effSBrian Somers break;
33928149effSBrian Somers #endif
34062e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
3412faae814SBrian Somers case IPPROTO_OSPFIGP:
34230949fd4SBrian Somers mindata = 8; /* IGMP uses 8-octet messages */
3432faae814SBrian Somers break;
34462e85934SBrian Somers #endif
34530949fd4SBrian Somers #ifndef NOINET6
34630949fd4SBrian Somers case IPPROTO_IPV6:
34730949fd4SBrian Somers mindata = 20; /* RFC2893 Section 3.5: 5 * 32bit words */
3482231246bSBrian Somers break;
34930949fd4SBrian Somers #endif
35006a43ce0SBrian Somers
35130949fd4SBrian Somers case IPPROTO_UDP:
35230949fd4SBrian Somers mindata = 8; /* UDP header is 8 octets */
35330949fd4SBrian Somers uh = (const struct udphdr *)payload;
354944f7098SBrian Somers sport = ntohs(uh->uh_sport);
355944f7098SBrian Somers dport = ntohs(uh->uh_dport);
356dd7e2610SBrian Somers if (log_IsKept(LogDEBUG))
3578390b576SBrian Somers snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
3588390b576SBrian Somers sport, dport);
359af57ed9fSAtsushi Murai break;
36030949fd4SBrian Somers
361af57ed9fSAtsushi Murai case IPPROTO_TCP:
36230949fd4SBrian Somers th = (const struct tcphdr *)payload;
36330949fd4SBrian Somers /*
36430949fd4SBrian Somers * TCP headers are variable length. The following code
365cad7e742SBrian Somers * ensures that the TCP header length isn't de-referenced if
366cad7e742SBrian Somers * the datagram is too short
367cad7e742SBrian Somers */
36806a43ce0SBrian Somers if (datalen < 20 || datalen < (th->th_off << 2)) {
36906a43ce0SBrian Somers log_Printf(LogFILTER, " error: TCP header incorrect\n");
3700a4b6c5cSBrian Somers return 1;
37106a43ce0SBrian Somers }
372944f7098SBrian Somers sport = ntohs(th->th_sport);
373944f7098SBrian Somers dport = ntohs(th->th_dport);
3740fc7bdc9SRichard Scheffenegger estab = __tcp_get_flags(th) & TH_ACK;
3750fc7bdc9SRichard Scheffenegger syn = __tcp_get_flags(th) & TH_SYN;
3760fc7bdc9SRichard Scheffenegger finrst = __tcp_get_flags(th) & (TH_FIN|TH_RST);
3772b81c773SBrian Somers if (log_IsKept(LogDEBUG)) {
3782b81c773SBrian Somers if (!estab)
3798390b576SBrian Somers snprintf(dbuff, sizeof dbuff,
3800fc7bdc9SRichard Scheffenegger "flags = %03x, sport = %d, dport = %d",
3810fc7bdc9SRichard Scheffenegger __tcp_get_flags(th), sport, dport);
3822b81c773SBrian Somers else
3832b81c773SBrian Somers *dbuff = '\0';
3842b81c773SBrian Somers }
385af57ed9fSAtsushi Murai break;
386af57ed9fSAtsushi Murai default:
38730949fd4SBrian Somers break;
38830949fd4SBrian Somers }
38930949fd4SBrian Somers
39030949fd4SBrian Somers if (datalen < mindata) {
39130949fd4SBrian Somers log_Printf(LogFILTER, " error: proto %s must be at least"
392e2ccf799SDiomidis Spinellis " %d octets\n", prototxt(cproto), mindata);
39330949fd4SBrian Somers return 1;
394af57ed9fSAtsushi Murai }
395cad7e742SBrian Somers
396dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) {
3978390b576SBrian Somers if (estab != -1) {
3988390b576SBrian Somers len = strlen(dbuff);
39963f98b41SBrian Somers snprintf(dbuff + len, sizeof dbuff - len,
40063f98b41SBrian Somers ", estab = %d, syn = %d, finrst = %d",
40163f98b41SBrian Somers estab, syn, finrst);
402af57ed9fSAtsushi Murai }
403e2ccf799SDiomidis Spinellis log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
404e2ccf799SDiomidis Spinellis prototxt(cproto), dbuff);
4058390b576SBrian Somers }
4068390b576SBrian Somers gotinfo = 1;
4078390b576SBrian Somers }
40830949fd4SBrian Somers
409dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) {
410cad7e742SBrian Somers if (fp->f_srcop != OP_NONE) {
4118390b576SBrian Somers snprintf(dbuff, sizeof dbuff, ", src %s %d",
412cad7e742SBrian Somers filter_Op2Nam(fp->f_srcop), fp->f_srcport);
4138390b576SBrian Somers len = strlen(dbuff);
4148390b576SBrian Somers } else
4158390b576SBrian Somers len = 0;
416cad7e742SBrian Somers if (fp->f_dstop != OP_NONE) {
4178390b576SBrian Somers snprintf(dbuff + len, sizeof dbuff - len,
418cad7e742SBrian Somers ", dst %s %d", filter_Op2Nam(fp->f_dstop),
419cad7e742SBrian Somers fp->f_dstport);
4208390b576SBrian Somers } else if (!len)
4218390b576SBrian Somers *dbuff = '\0';
4228390b576SBrian Somers
423dd7e2610SBrian Somers log_Printf(LogDEBUG, " rule = %d: Address match, "
42430949fd4SBrian Somers "check against proto %d%s, action = %s\n",
42530949fd4SBrian Somers n, fp->f_proto, dbuff, filter_Action2Nam(fp->f_action));
4268390b576SBrian Somers }
427927145beSBrian Somers
428cad7e742SBrian Somers if (cproto == fp->f_proto) {
429cad7e742SBrian Somers if ((fp->f_srcop == OP_NONE ||
430cad7e742SBrian Somers PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
431cad7e742SBrian Somers (fp->f_dstop == OP_NONE ||
432cad7e742SBrian Somers PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
433cad7e742SBrian Somers (fp->f_estab == 0 || estab) &&
434cad7e742SBrian Somers (fp->f_syn == 0 || syn) &&
435cad7e742SBrian Somers (fp->f_finrst == 0 || finrst)) {
436cad7e742SBrian Somers match = 1;
437af57ed9fSAtsushi Murai }
438af57ed9fSAtsushi Murai }
439af57ed9fSAtsushi Murai } else {
440cad7e742SBrian Somers /* Address is matched and no protocol specified. Make a decision. */
441dd7e2610SBrian Somers log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n,
442cad7e742SBrian Somers filter_Action2Nam(fp->f_action));
443cad7e742SBrian Somers match = 1;
444af57ed9fSAtsushi Murai }
4458390b576SBrian Somers } else
446dd7e2610SBrian Somers log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n);
447cad7e742SBrian Somers
448cad7e742SBrian Somers if (match != fp->f_invert) {
449cad7e742SBrian Somers /* Take specified action */
450cad7e742SBrian Somers if (fp->f_action < A_NONE)
451cad7e742SBrian Somers fp = &filter->rule[n = fp->f_action];
45206a43ce0SBrian Somers else {
4530a4b6c5cSBrian Somers if (fp->f_action == A_PERMIT) {
4540a4b6c5cSBrian Somers if (psecs != NULL)
4550a4b6c5cSBrian Somers *psecs = fp->timeout;
45606a43ce0SBrian Somers if (strcmp(filter->name, "DIAL") == 0) {
45706a43ce0SBrian Somers /* If dial filter then even print out accept packets */
45806a43ce0SBrian Somers if (log_IsKept(LogFILTER)) {
45930949fd4SBrian Somers snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
46006a43ce0SBrian Somers log_Printf(LogFILTER, "%sbound rule = %d accept %s "
461e2ccf799SDiomidis Spinellis "src = %s:%d dst = %s:%d\n", filter->name, n,
462e2ccf799SDiomidis Spinellis prototxt(cproto), ncpaddr_ntoa(&srcaddr), sport,
463e2ccf799SDiomidis Spinellis dstip, dport);
46406a43ce0SBrian Somers }
46506a43ce0SBrian Somers }
4660a4b6c5cSBrian Somers return 0;
46706a43ce0SBrian Somers } else {
46806a43ce0SBrian Somers if (log_IsKept(LogFILTER)) {
46930949fd4SBrian Somers snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
47006a43ce0SBrian Somers log_Printf(LogFILTER,
47106a43ce0SBrian Somers "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
472e2ccf799SDiomidis Spinellis filter->name, n, prototxt(cproto),
47330949fd4SBrian Somers ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
47406a43ce0SBrian Somers }
4750a4b6c5cSBrian Somers return 1;
476463a577bSEitan Adler } /* Explicit match. Deny this packet */
47706a43ce0SBrian Somers }
478cad7e742SBrian Somers } else {
479cad7e742SBrian Somers n++;
480af57ed9fSAtsushi Murai fp++;
481af57ed9fSAtsushi Murai }
482af57ed9fSAtsushi Murai }
48306a43ce0SBrian Somers
48406a43ce0SBrian Somers if (log_IsKept(LogFILTER)) {
48530949fd4SBrian Somers snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
48606a43ce0SBrian Somers log_Printf(LogFILTER,
48706a43ce0SBrian Somers "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
488e2ccf799SDiomidis Spinellis filter->name, prototxt(cproto), ncpaddr_ntoa(&srcaddr),
489e2ccf799SDiomidis Spinellis sport, dstip, dport);
49006a43ce0SBrian Somers }
49106a43ce0SBrian Somers
49230949fd4SBrian Somers return 1; /* No rule matched, deny this packet */
493af57ed9fSAtsushi Murai }
494af57ed9fSAtsushi Murai
49552c9ca19SBrian Somers static void
ip_LogDNS(const struct udphdr * uh,const char * direction)49652c9ca19SBrian Somers ip_LogDNS(const struct udphdr *uh, const char *direction)
49752c9ca19SBrian Somers {
49852c9ca19SBrian Somers struct dns_header header;
49952c9ca19SBrian Somers const u_short *pktptr;
50052c9ca19SBrian Somers const u_char *ptr;
50147fe010cSBrian Somers u_short *hptr, tmp;
502057f1760SBrian Somers unsigned len;
50352c9ca19SBrian Somers
50452c9ca19SBrian Somers ptr = (const char *)uh + sizeof *uh;
50552c9ca19SBrian Somers len = ntohs(uh->uh_ulen) - sizeof *uh;
50652c9ca19SBrian Somers if (len < sizeof header + 5) /* rfc1024 */
50752c9ca19SBrian Somers return;
50852c9ca19SBrian Somers
50952c9ca19SBrian Somers pktptr = (const u_short *)ptr;
51052c9ca19SBrian Somers hptr = (u_short *)&header;
51152c9ca19SBrian Somers ptr += sizeof header;
51252c9ca19SBrian Somers len -= sizeof header;
51352c9ca19SBrian Somers
51452c9ca19SBrian Somers while (pktptr < (const u_short *)ptr) {
51552c9ca19SBrian Somers *hptr++ = ntohs(*pktptr); /* Careful of macro side-effects ! */
51652c9ca19SBrian Somers pktptr++;
51752c9ca19SBrian Somers }
51852c9ca19SBrian Somers
51952c9ca19SBrian Somers if (header.opcode == OPCODE_QUERY && header.qr == 0) {
52052c9ca19SBrian Somers /* rfc1035 */
52126e6a622SBrian Somers char namewithdot[MAXHOSTNAMELEN + 1], *n;
52252c9ca19SBrian Somers const char *qtype, *qclass;
52352c9ca19SBrian Somers const u_char *end;
52452c9ca19SBrian Somers
52526e6a622SBrian Somers n = namewithdot;
52652c9ca19SBrian Somers end = ptr + len - 4;
527057f1760SBrian Somers if (end - ptr >= (int)sizeof namewithdot)
52826e6a622SBrian Somers end = ptr + sizeof namewithdot - 1;
52952c9ca19SBrian Somers while (ptr < end) {
53052c9ca19SBrian Somers len = *ptr++;
531057f1760SBrian Somers if ((int)len > end - ptr)
53252c9ca19SBrian Somers len = end - ptr;
53326e6a622SBrian Somers if (n != namewithdot)
53452c9ca19SBrian Somers *n++ = '.';
53552c9ca19SBrian Somers memcpy(n, ptr, len);
53652c9ca19SBrian Somers ptr += len;
53752c9ca19SBrian Somers n += len;
53852c9ca19SBrian Somers }
53952c9ca19SBrian Somers *n = '\0';
54047fe010cSBrian Somers
54147fe010cSBrian Somers if (log_IsKept(LogDNS)) {
54247fe010cSBrian Somers memcpy(&tmp, end, sizeof tmp);
54347fe010cSBrian Somers qtype = dns_Qtype2Txt(ntohs(tmp));
54447fe010cSBrian Somers memcpy(&tmp, end + 2, sizeof tmp);
54547fe010cSBrian Somers qclass = dns_Qclass2Txt(ntohs(tmp));
54652c9ca19SBrian Somers
54752c9ca19SBrian Somers log_Printf(LogDNS, "%sbound query %s %s %s\n",
54826e6a622SBrian Somers direction, qclass, qtype, namewithdot);
54952c9ca19SBrian Somers }
55052c9ca19SBrian Somers }
55147fe010cSBrian Somers }
55252c9ca19SBrian Somers
553af57ed9fSAtsushi Murai /*
55430949fd4SBrian Somers * Check if the given packet matches the given filter.
55530949fd4SBrian Somers * One of pip or pip6 must be set.
556af57ed9fSAtsushi Murai */
557af57ed9fSAtsushi Murai int
PacketCheck(struct bundle * bundle,u_int32_t family,const unsigned char * packet,int nb,struct filter * filter,const char * prefix,unsigned * psecs)55830949fd4SBrian Somers PacketCheck(struct bundle *bundle, u_int32_t family,
55930949fd4SBrian Somers const unsigned char *packet, int nb, struct filter *filter,
56030949fd4SBrian Somers const char *prefix, unsigned *psecs)
561af57ed9fSAtsushi Murai {
562057f1760SBrian Somers char logbuf[200];
56352c9ca19SBrian Somers static const char *const TcpFlags[] = {
564347dd053SRichard Scheffenegger "FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECE", "CWR", "AE"
56552c9ca19SBrian Somers };
56630949fd4SBrian Somers const struct tcphdr *th;
56730949fd4SBrian Somers const struct udphdr *uh;
56830949fd4SBrian Somers const struct icmp *icmph;
56930949fd4SBrian Somers #ifndef NOINET6
57030949fd4SBrian Somers const struct icmp6_hdr *icmp6h;
57130949fd4SBrian Somers #endif
57230949fd4SBrian Somers const unsigned char *payload;
57330949fd4SBrian Somers struct ncpaddr srcaddr, dstaddr;
574057f1760SBrian Somers int cproto, mask, len, n, pri, logit, result, datalen, frag;
575057f1760SBrian Somers unsigned loglen;
57630949fd4SBrian Somers u_char tos;
577af57ed9fSAtsushi Murai
578b565321aSBrian Somers logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
579b565321aSBrian Somers (!filter || filter->logok);
58055a8cdeaSBrian Somers loglen = 0;
58152c9ca19SBrian Somers pri = 0;
582af57ed9fSAtsushi Murai
58330949fd4SBrian Somers #ifndef NOINET6
58430949fd4SBrian Somers if (family == AF_INET6) {
58530949fd4SBrian Somers const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
58630949fd4SBrian Somers
58730949fd4SBrian Somers ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
58830949fd4SBrian Somers ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
58930949fd4SBrian Somers datalen = ntohs(pip6->ip6_plen);
59030949fd4SBrian Somers payload = packet + sizeof *pip6;
59130949fd4SBrian Somers cproto = pip6->ip6_nxt;
5926de54bbeSBrian Somers tos = 0; /* XXX: pip6->ip6_vfc >> 4 ? */
59330949fd4SBrian Somers frag = 0; /* XXX: ??? */
59430949fd4SBrian Somers } else
59530949fd4SBrian Somers #endif
59630949fd4SBrian Somers {
59730949fd4SBrian Somers const struct ip *pip = (const struct ip *)packet;
59830949fd4SBrian Somers
59930949fd4SBrian Somers ncpaddr_setip4(&srcaddr, pip->ip_src);
60030949fd4SBrian Somers ncpaddr_setip4(&dstaddr, pip->ip_dst);
60130949fd4SBrian Somers datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
60230949fd4SBrian Somers payload = packet + (pip->ip_hl << 2);
60330949fd4SBrian Somers cproto = pip->ip_p;
60430949fd4SBrian Somers tos = pip->ip_tos;
60530949fd4SBrian Somers frag = ntohs(pip->ip_off) & IP_OFFMASK;
60630949fd4SBrian Somers }
60730949fd4SBrian Somers
60852c9ca19SBrian Somers uh = NULL;
609af57ed9fSAtsushi Murai
61055a8cdeaSBrian Somers if (logit && loglen < sizeof logbuf) {
61198251667SBrian Somers if (prefix)
61298251667SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix);
61398251667SBrian Somers else if (filter)
6145ca5389aSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
615b565321aSBrian Somers else
616b565321aSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " ");
61755a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
61855a8cdeaSBrian Somers }
619af57ed9fSAtsushi Murai
62030949fd4SBrian Somers switch (cproto) {
621af57ed9fSAtsushi Murai case IPPROTO_ICMP:
62255a8cdeaSBrian Somers if (logit && loglen < sizeof logbuf) {
62330949fd4SBrian Somers len = datalen - sizeof *icmph;
62430949fd4SBrian Somers icmph = (const struct icmp *)payload;
62555a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
62630949fd4SBrian Somers "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmph->icmp_type);
62755a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
62855a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
62930949fd4SBrian Somers "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
63055a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
631af57ed9fSAtsushi Murai }
632af57ed9fSAtsushi Murai break;
633da477886SBrian Somers
63430949fd4SBrian Somers #ifndef NOINET6
63530949fd4SBrian Somers case IPPROTO_ICMPV6:
63630949fd4SBrian Somers if (logit && loglen < sizeof logbuf) {
63730949fd4SBrian Somers len = datalen - sizeof *icmp6h;
63830949fd4SBrian Somers icmp6h = (const struct icmp6_hdr *)payload;
63930949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
64030949fd4SBrian Somers "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmp6h->icmp6_type);
64130949fd4SBrian Somers loglen += strlen(logbuf + loglen);
64230949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
64330949fd4SBrian Somers "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
64430949fd4SBrian Somers loglen += strlen(logbuf + loglen);
64530949fd4SBrian Somers }
64630949fd4SBrian Somers break;
64730949fd4SBrian Somers #endif
64830949fd4SBrian Somers
649af57ed9fSAtsushi Murai case IPPROTO_UDP:
65030949fd4SBrian Somers uh = (const struct udphdr *)payload;
65130949fd4SBrian Somers if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
652da477886SBrian Somers pri++;
653da477886SBrian Somers
65430949fd4SBrian Somers if (!frag && ncp_IsUrgentUdpPort(&bundle->ncp, ntohs(uh->uh_sport),
655da477886SBrian Somers ntohs(uh->uh_dport)))
656da477886SBrian Somers pri++;
657da477886SBrian Somers
658da477886SBrian Somers if (logit && loglen < sizeof logbuf) {
65930949fd4SBrian Somers len = datalen - sizeof *uh;
66055a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
66130949fd4SBrian Somers "UDP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport));
66255a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
66355a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
66430949fd4SBrian Somers "%s:%d (%d/%d)", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport),
66598251667SBrian Somers len, nb);
66655a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
667af57ed9fSAtsushi Murai }
66898251667SBrian Somers
66998251667SBrian Somers if (Enabled(bundle, OPT_FILTERDECAP) &&
67030949fd4SBrian Somers payload[sizeof *uh] == HDLC_ADDR &&
67130949fd4SBrian Somers payload[sizeof *uh + 1] == HDLC_UI) {
67298251667SBrian Somers u_short proto;
67398251667SBrian Somers const char *type;
67498251667SBrian Somers
67530949fd4SBrian Somers memcpy(&proto, payload + sizeof *uh + 2, sizeof proto);
67698251667SBrian Somers type = NULL;
67798251667SBrian Somers
67898251667SBrian Somers switch (ntohs(proto)) {
67998251667SBrian Somers case PROTO_IP:
68098251667SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
68130949fd4SBrian Somers result = PacketCheck(bundle, AF_INET, payload + sizeof *uh + 4,
68230949fd4SBrian Somers nb - (payload - packet) - sizeof *uh - 4, filter,
6830a4b6c5cSBrian Somers logbuf, psecs);
68498251667SBrian Somers if (result != -2)
68598251667SBrian Somers return result;
68698251667SBrian Somers type = "IP";
68798251667SBrian Somers break;
68898251667SBrian Somers
68998251667SBrian Somers case PROTO_VJUNCOMP: type = "compressed VJ"; break;
69098251667SBrian Somers case PROTO_VJCOMP: type = "uncompressed VJ"; break;
69198251667SBrian Somers case PROTO_MP: type = "Multi-link"; break;
69298251667SBrian Somers case PROTO_ICOMPD: type = "Individual link CCP"; break;
69398251667SBrian Somers case PROTO_COMPD: type = "CCP"; break;
69498251667SBrian Somers case PROTO_IPCP: type = "IPCP"; break;
69598251667SBrian Somers case PROTO_LCP: type = "LCP"; break;
69698251667SBrian Somers case PROTO_PAP: type = "PAP"; break;
69798251667SBrian Somers case PROTO_CBCP: type = "CBCP"; break;
69898251667SBrian Somers case PROTO_LQR: type = "LQR"; break;
69998251667SBrian Somers case PROTO_CHAP: type = "CHAP"; break;
70098251667SBrian Somers }
70198251667SBrian Somers if (type) {
70298251667SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
70398251667SBrian Somers " - %s data", type);
70498251667SBrian Somers loglen += strlen(logbuf + loglen);
70598251667SBrian Somers }
70698251667SBrian Somers }
70798251667SBrian Somers
708af57ed9fSAtsushi Murai break;
709da477886SBrian Somers
71028149effSBrian Somers #ifdef IPPROTO_GRE
71128149effSBrian Somers case IPPROTO_GRE:
71228149effSBrian Somers if (logit && loglen < sizeof logbuf) {
71328149effSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
71430949fd4SBrian Somers "GRE: %s ---> ", ncpaddr_ntoa(&srcaddr));
71528149effSBrian Somers loglen += strlen(logbuf + loglen);
71628149effSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
71730949fd4SBrian Somers "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
71828149effSBrian Somers loglen += strlen(logbuf + loglen);
71928149effSBrian Somers }
72028149effSBrian Somers break;
72128149effSBrian Somers #endif
72228149effSBrian Somers
72362e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
7242faae814SBrian Somers case IPPROTO_OSPFIGP:
7252faae814SBrian Somers if (logit && loglen < sizeof logbuf) {
7262faae814SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
72730949fd4SBrian Somers "OSPF: %s ---> ", ncpaddr_ntoa(&srcaddr));
7282faae814SBrian Somers loglen += strlen(logbuf + loglen);
7292faae814SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
73030949fd4SBrian Somers "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
7312faae814SBrian Somers loglen += strlen(logbuf + loglen);
7322faae814SBrian Somers }
7332faae814SBrian Somers break;
73462e85934SBrian Somers #endif
735da477886SBrian Somers
73630949fd4SBrian Somers #ifndef NOINET6
73730949fd4SBrian Somers case IPPROTO_IPV6:
73830949fd4SBrian Somers if (logit && loglen < sizeof logbuf) {
73930949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
74030949fd4SBrian Somers "IPv6: %s ---> ", ncpaddr_ntoa(&srcaddr));
74130949fd4SBrian Somers loglen += strlen(logbuf + loglen);
74230949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
74330949fd4SBrian Somers "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
74430949fd4SBrian Somers loglen += strlen(logbuf + loglen);
74530949fd4SBrian Somers }
74630949fd4SBrian Somers
74730949fd4SBrian Somers if (Enabled(bundle, OPT_FILTERDECAP)) {
74830949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
74930949fd4SBrian Somers result = PacketCheck(bundle, AF_INET6, payload, nb - (payload - packet),
75030949fd4SBrian Somers filter, logbuf, psecs);
75130949fd4SBrian Somers if (result != -2)
75230949fd4SBrian Somers return result;
75330949fd4SBrian Somers }
75430949fd4SBrian Somers break;
75530949fd4SBrian Somers #endif
75630949fd4SBrian Somers
757eee772ecSBrian Somers case IPPROTO_IPIP:
758eee772ecSBrian Somers if (logit && loglen < sizeof logbuf) {
759eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
76030949fd4SBrian Somers "IPIP: %s ---> ", ncpaddr_ntoa(&srcaddr));
761eee772ecSBrian Somers loglen += strlen(logbuf + loglen);
762eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
76330949fd4SBrian Somers "%s", ncpaddr_ntoa(&dstaddr));
764eee772ecSBrian Somers loglen += strlen(logbuf + loglen);
76530949fd4SBrian Somers }
766da70ad60SBrian Somers
76730949fd4SBrian Somers if (Enabled(bundle, OPT_FILTERDECAP) &&
76830949fd4SBrian Somers ((const struct ip *)payload)->ip_v == 4) {
769da70ad60SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
77030949fd4SBrian Somers result = PacketCheck(bundle, AF_INET, payload, nb - (payload - packet),
77130949fd4SBrian Somers filter, logbuf, psecs);
772057f1760SBrian Somers loglen += strlen(logbuf + loglen);
773da70ad60SBrian Somers if (result != -2)
774da70ad60SBrian Somers return result;
775da70ad60SBrian Somers }
776eee772ecSBrian Somers break;
777da477886SBrian Somers
7782231246bSBrian Somers case IPPROTO_ESP:
7792231246bSBrian Somers if (logit && loglen < sizeof logbuf) {
7802231246bSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
78130949fd4SBrian Somers "ESP: %s ---> ", ncpaddr_ntoa(&srcaddr));
7822231246bSBrian Somers loglen += strlen(logbuf + loglen);
78325254215SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
78430949fd4SBrian Somers ncpaddr_ntoa(&dstaddr), payload);
7852231246bSBrian Somers loglen += strlen(logbuf + loglen);
7862231246bSBrian Somers }
7872231246bSBrian Somers break;
7882231246bSBrian Somers
7892231246bSBrian Somers case IPPROTO_AH:
7902231246bSBrian Somers if (logit && loglen < sizeof logbuf) {
7912231246bSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
79230949fd4SBrian Somers "AH: %s ---> ", ncpaddr_ntoa(&srcaddr));
7932231246bSBrian Somers loglen += strlen(logbuf + loglen);
79425254215SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
79530949fd4SBrian Somers ncpaddr_ntoa(&dstaddr), payload + sizeof(u_int32_t));
7962231246bSBrian Somers loglen += strlen(logbuf + loglen);
7972231246bSBrian Somers }
7982231246bSBrian Somers break;
7992231246bSBrian Somers
800eee772ecSBrian Somers case IPPROTO_IGMP:
801eee772ecSBrian Somers if (logit && loglen < sizeof logbuf) {
80230949fd4SBrian Somers uh = (const struct udphdr *)payload;
803eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
80430949fd4SBrian Somers "IGMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr),
8050a4b6c5cSBrian Somers ntohs(uh->uh_sport));
806eee772ecSBrian Somers loglen += strlen(logbuf + loglen);
807eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
80830949fd4SBrian Somers "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport));
809eee772ecSBrian Somers loglen += strlen(logbuf + loglen);
810eee772ecSBrian Somers }
811eee772ecSBrian Somers break;
812da477886SBrian Somers
813af57ed9fSAtsushi Murai case IPPROTO_TCP:
81430949fd4SBrian Somers th = (const struct tcphdr *)payload;
81530949fd4SBrian Somers if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
816442f8495SBrian Somers pri++;
817da477886SBrian Somers
81830949fd4SBrian Somers if (!frag && ncp_IsUrgentTcpPort(&bundle->ncp, ntohs(th->th_sport),
819442f8495SBrian Somers ntohs(th->th_dport)))
820442f8495SBrian Somers pri++;
821f80b39d1SNick Hibma else if (!frag && ncp_IsUrgentTcpLen(&bundle->ncp, datalen))
822f80b39d1SNick Hibma pri++;
823442f8495SBrian Somers
82455a8cdeaSBrian Somers if (logit && loglen < sizeof logbuf) {
82530949fd4SBrian Somers len = datalen - (th->th_off << 2);
82655a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
82730949fd4SBrian Somers "TCP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(th->th_sport));
82855a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
82955a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
83030949fd4SBrian Somers "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(th->th_dport));
83155a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
832*31034044SRichard Scheffenegger for (mask = TH_FIN, n = 0; mask <= TH_FLAGS; mask <<= 1, n++) {
8330fc7bdc9SRichard Scheffenegger if (__tcp_get_flags(th) & mask) {
83455a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
83555a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
83655a8cdeaSBrian Somers }
837af57ed9fSAtsushi Murai }
83855a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
8393a2e4f62SBrian Somers " seq:%lx ack:%lx (%d/%d)",
8403a2e4f62SBrian Somers (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
84155a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
8420fc7bdc9SRichard Scheffenegger if ((__tcp_get_flags(th) & TH_SYN) && nb > 40) {
84330949fd4SBrian Somers const u_short *sp;
844af57ed9fSAtsushi Murai
84530949fd4SBrian Somers sp = (const u_short *)(payload + 20);
84655a8cdeaSBrian Somers if (ntohs(sp[0]) == 0x0204) {
84755a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
84855a8cdeaSBrian Somers " MSS = %d", ntohs(sp[1]));
84955a8cdeaSBrian Somers loglen += strlen(logbuf + loglen);
85055a8cdeaSBrian Somers }
851af57ed9fSAtsushi Murai }
852f80b39d1SNick Hibma snprintf(logbuf + loglen, sizeof logbuf - loglen, " pri:%d", pri);
853f80b39d1SNick Hibma loglen += strlen(logbuf + loglen);
854af57ed9fSAtsushi Murai }
855af57ed9fSAtsushi Murai break;
85698251667SBrian Somers
85798251667SBrian Somers default:
85898251667SBrian Somers if (prefix)
85998251667SBrian Somers return -2;
86030949fd4SBrian Somers
86130949fd4SBrian Somers if (logit && loglen < sizeof logbuf) {
86230949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
86330949fd4SBrian Somers "<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr));
86430949fd4SBrian Somers loglen += strlen(logbuf + loglen);
86530949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen,
86630949fd4SBrian Somers "%s (%d)", ncpaddr_ntoa(&dstaddr), nb);
86730949fd4SBrian Somers loglen += strlen(logbuf + loglen);
86830949fd4SBrian Somers }
86930949fd4SBrian Somers break;
870af57ed9fSAtsushi Murai }
87176bd0c0aSDoug Rabson
87230949fd4SBrian Somers if (filter && FilterCheck(packet, family, filter, psecs)) {
873710e9c29SBrian Somers if (logit)
874dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
87552c9ca19SBrian Somers result = -1;
876af57ed9fSAtsushi Murai } else {
8775ca5389aSBrian Somers /* Check Keep Alive filter */
87852c9ca19SBrian Somers if (logit && log_IsKept(LogTCPIP)) {
8790a4b6c5cSBrian Somers unsigned alivesecs;
8800a4b6c5cSBrian Somers
8810a4b6c5cSBrian Somers alivesecs = 0;
88230949fd4SBrian Somers if (filter &&
88330949fd4SBrian Somers FilterCheck(packet, family, &bundle->filter.alive, &alivesecs))
884dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
8850a4b6c5cSBrian Somers else if (psecs != NULL) {
8860a4b6c5cSBrian Somers if(*psecs == 0)
8870a4b6c5cSBrian Somers *psecs = alivesecs;
8880a4b6c5cSBrian Somers if (*psecs) {
8890a4b6c5cSBrian Somers if (*psecs != alivesecs)
8900a4b6c5cSBrian Somers log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n",
8910a4b6c5cSBrian Somers logbuf, *psecs, alivesecs);
8921e991daaSBrian Somers else
8930a4b6c5cSBrian Somers log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs);
8940a4b6c5cSBrian Somers } else
895dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s\n", logbuf);
89653c9f6c0SAtsushi Murai }
8970a4b6c5cSBrian Somers }
89852c9ca19SBrian Somers result = pri;
899af57ed9fSAtsushi Murai }
90052c9ca19SBrian Somers
901b565321aSBrian Somers if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
90252c9ca19SBrian Somers ip_LogDNS(uh, filter->name);
90352c9ca19SBrian Somers
90452c9ca19SBrian Somers return result;
905af57ed9fSAtsushi Murai }
906af57ed9fSAtsushi Murai
907057f1760SBrian Somers static size_t
ip_Input(struct bundle * bundle,struct link * l,struct mbuf * bp,u_int32_t af)90830949fd4SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af)
9097a6f8720SBrian Somers {
910057f1760SBrian Somers ssize_t nw;
911057f1760SBrian Somers size_t nb;
912b6e82f33SBrian Somers struct tun_data tun;
9133a7b6d76SBrian Somers char *data;
9140a4b6c5cSBrian Somers unsigned secs, alivesecs;
9155d9e6103SBrian Somers
91626af0ae9SBrian Somers nb = m_length(bp);
91776d98538SBrian Somers if (nb > sizeof tun.data) {
9181814213eSMarcel Moolenaar log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %zd, max %d)\n",
91976d98538SBrian Somers l->name, nb, (int)(sizeof tun.data));
92026af0ae9SBrian Somers m_freem(bp);
92130949fd4SBrian Somers return 0;
92276d98538SBrian Somers }
9235d9e6103SBrian Somers mbuf_Read(bp, tun.data, nb);
924af57ed9fSAtsushi Murai
9250a4b6c5cSBrian Somers secs = 0;
92630949fd4SBrian Somers if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in,
92730949fd4SBrian Somers NULL, &secs) < 0)
92830949fd4SBrian Somers return 0;
9296db75539SBrian Somers
9300a4b6c5cSBrian Somers alivesecs = 0;
93130949fd4SBrian Somers if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) {
9320a4b6c5cSBrian Somers if (secs == 0)
9330a4b6c5cSBrian Somers secs = alivesecs;
9340a4b6c5cSBrian Somers bundle_StartIdleTimer(bundle, secs);
9350a4b6c5cSBrian Somers }
9361e991daaSBrian Somers
9373a7b6d76SBrian Somers if (bundle->dev.header) {
93830949fd4SBrian Somers tun.header.family = htonl(af);
93970ee81ffSBrian Somers nb += sizeof tun - sizeof tun.data;
9403a7b6d76SBrian Somers data = (char *)&tun;
9413a7b6d76SBrian Somers } else
9423a7b6d76SBrian Somers data = tun.data;
9433a7b6d76SBrian Somers
9443a7b6d76SBrian Somers nw = write(bundle->dev.fd, data, nb);
945057f1760SBrian Somers if (nw != (ssize_t)nb) {
94657fd05c4SBrian Somers if (nw == -1)
9471814213eSMarcel Moolenaar log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %s\n",
94876d98538SBrian Somers l->name, nb, strerror(errno));
94957fd05c4SBrian Somers else
9501814213eSMarcel Moolenaar log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %zd\n", l->name, nb,
9511814213eSMarcel Moolenaar nw);
9526db75539SBrian Somers }
9535d9e6103SBrian Somers
95430949fd4SBrian Somers return nb;
95530949fd4SBrian Somers }
95630949fd4SBrian Somers
95730949fd4SBrian Somers struct mbuf *
ipv4_Input(struct bundle * bundle,struct link * l,struct mbuf * bp)95830949fd4SBrian Somers ipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
95930949fd4SBrian Somers {
96030949fd4SBrian Somers int nb;
96130949fd4SBrian Somers
96230949fd4SBrian Somers if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
96330949fd4SBrian Somers log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n");
96430949fd4SBrian Somers m_freem(bp);
9655d9e6103SBrian Somers return NULL;
966af57ed9fSAtsushi Murai }
967af57ed9fSAtsushi Murai
96830949fd4SBrian Somers m_settype(bp, MB_IPIN);
96930949fd4SBrian Somers
97030949fd4SBrian Somers nb = ip_Input(bundle, l, bp, AF_INET);
97130949fd4SBrian Somers ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
97230949fd4SBrian Somers
97330949fd4SBrian Somers return NULL;
97430949fd4SBrian Somers }
97530949fd4SBrian Somers
97630949fd4SBrian Somers #ifndef NOINET6
97730949fd4SBrian Somers struct mbuf *
ipv6_Input(struct bundle * bundle,struct link * l,struct mbuf * bp)97830949fd4SBrian Somers ipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
979af57ed9fSAtsushi Murai {
98030949fd4SBrian Somers int nb;
981af57ed9fSAtsushi Murai
9821136c6acSBrian Somers if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) {
98330949fd4SBrian Somers log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n");
98430949fd4SBrian Somers m_freem(bp);
98530949fd4SBrian Somers return NULL;
986af57ed9fSAtsushi Murai }
987af57ed9fSAtsushi Murai
98830949fd4SBrian Somers m_settype(bp, MB_IPV6IN);
9896f8e9f0aSBrian Somers
99030949fd4SBrian Somers nb = ip_Input(bundle, l, bp, AF_INET6);
99130949fd4SBrian Somers ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb);
99230949fd4SBrian Somers
99330949fd4SBrian Somers return NULL;
9946f8e9f0aSBrian Somers }
99530949fd4SBrian Somers #endif
996