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 * 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 * 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 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 * 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 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); 374*0fc7bdc9SRichard Scheffenegger estab = __tcp_get_flags(th) & TH_ACK; 375*0fc7bdc9SRichard Scheffenegger syn = __tcp_get_flags(th) & TH_SYN; 376*0fc7bdc9SRichard 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, 380*0fc7bdc9SRichard Scheffenegger "flags = %03x, sport = %d, dport = %d", 381*0fc7bdc9SRichard 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 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 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[] = { 56452c9ca19SBrian Somers "FIN", "SYN", "RST", "PSH", "ACK", "URG" 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); 832af57ed9fSAtsushi Murai n = 0; 833af57ed9fSAtsushi Murai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 834*0fc7bdc9SRichard Scheffenegger if (__tcp_get_flags(th) & mask) { 83555a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 83655a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 83755a8cdeaSBrian Somers } 838af57ed9fSAtsushi Murai n++; 839af57ed9fSAtsushi Murai } 84055a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 8413a2e4f62SBrian Somers " seq:%lx ack:%lx (%d/%d)", 8423a2e4f62SBrian Somers (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 84355a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 844*0fc7bdc9SRichard Scheffenegger if ((__tcp_get_flags(th) & TH_SYN) && nb > 40) { 84530949fd4SBrian Somers const u_short *sp; 846af57ed9fSAtsushi Murai 84730949fd4SBrian Somers sp = (const u_short *)(payload + 20); 84855a8cdeaSBrian Somers if (ntohs(sp[0]) == 0x0204) { 84955a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 85055a8cdeaSBrian Somers " MSS = %d", ntohs(sp[1])); 85155a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 85255a8cdeaSBrian Somers } 853af57ed9fSAtsushi Murai } 854f80b39d1SNick Hibma snprintf(logbuf + loglen, sizeof logbuf - loglen, " pri:%d", pri); 855f80b39d1SNick Hibma loglen += strlen(logbuf + loglen); 856af57ed9fSAtsushi Murai } 857af57ed9fSAtsushi Murai break; 85898251667SBrian Somers 85998251667SBrian Somers default: 86098251667SBrian Somers if (prefix) 86198251667SBrian Somers return -2; 86230949fd4SBrian Somers 86330949fd4SBrian Somers if (logit && loglen < sizeof logbuf) { 86430949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 86530949fd4SBrian Somers "<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr)); 86630949fd4SBrian Somers loglen += strlen(logbuf + loglen); 86730949fd4SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 86830949fd4SBrian Somers "%s (%d)", ncpaddr_ntoa(&dstaddr), nb); 86930949fd4SBrian Somers loglen += strlen(logbuf + loglen); 87030949fd4SBrian Somers } 87130949fd4SBrian Somers break; 872af57ed9fSAtsushi Murai } 87376bd0c0aSDoug Rabson 87430949fd4SBrian Somers if (filter && FilterCheck(packet, family, filter, psecs)) { 875710e9c29SBrian Somers if (logit) 876dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 87752c9ca19SBrian Somers result = -1; 878af57ed9fSAtsushi Murai } else { 8795ca5389aSBrian Somers /* Check Keep Alive filter */ 88052c9ca19SBrian Somers if (logit && log_IsKept(LogTCPIP)) { 8810a4b6c5cSBrian Somers unsigned alivesecs; 8820a4b6c5cSBrian Somers 8830a4b6c5cSBrian Somers alivesecs = 0; 88430949fd4SBrian Somers if (filter && 88530949fd4SBrian Somers FilterCheck(packet, family, &bundle->filter.alive, &alivesecs)) 886dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 8870a4b6c5cSBrian Somers else if (psecs != NULL) { 8880a4b6c5cSBrian Somers if(*psecs == 0) 8890a4b6c5cSBrian Somers *psecs = alivesecs; 8900a4b6c5cSBrian Somers if (*psecs) { 8910a4b6c5cSBrian Somers if (*psecs != alivesecs) 8920a4b6c5cSBrian Somers log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n", 8930a4b6c5cSBrian Somers logbuf, *psecs, alivesecs); 8941e991daaSBrian Somers else 8950a4b6c5cSBrian Somers log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs); 8960a4b6c5cSBrian Somers } else 897dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s\n", logbuf); 89853c9f6c0SAtsushi Murai } 8990a4b6c5cSBrian Somers } 90052c9ca19SBrian Somers result = pri; 901af57ed9fSAtsushi Murai } 90252c9ca19SBrian Somers 903b565321aSBrian Somers if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS)) 90452c9ca19SBrian Somers ip_LogDNS(uh, filter->name); 90552c9ca19SBrian Somers 90652c9ca19SBrian Somers return result; 907af57ed9fSAtsushi Murai } 908af57ed9fSAtsushi Murai 909057f1760SBrian Somers static size_t 91030949fd4SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af) 9117a6f8720SBrian Somers { 912057f1760SBrian Somers ssize_t nw; 913057f1760SBrian Somers size_t nb; 914b6e82f33SBrian Somers struct tun_data tun; 9153a7b6d76SBrian Somers char *data; 9160a4b6c5cSBrian Somers unsigned secs, alivesecs; 9175d9e6103SBrian Somers 91826af0ae9SBrian Somers nb = m_length(bp); 91976d98538SBrian Somers if (nb > sizeof tun.data) { 9201814213eSMarcel Moolenaar log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %zd, max %d)\n", 92176d98538SBrian Somers l->name, nb, (int)(sizeof tun.data)); 92226af0ae9SBrian Somers m_freem(bp); 92330949fd4SBrian Somers return 0; 92476d98538SBrian Somers } 9255d9e6103SBrian Somers mbuf_Read(bp, tun.data, nb); 926af57ed9fSAtsushi Murai 9270a4b6c5cSBrian Somers secs = 0; 92830949fd4SBrian Somers if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in, 92930949fd4SBrian Somers NULL, &secs) < 0) 93030949fd4SBrian Somers return 0; 9316db75539SBrian Somers 9320a4b6c5cSBrian Somers alivesecs = 0; 93330949fd4SBrian Somers if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) { 9340a4b6c5cSBrian Somers if (secs == 0) 9350a4b6c5cSBrian Somers secs = alivesecs; 9360a4b6c5cSBrian Somers bundle_StartIdleTimer(bundle, secs); 9370a4b6c5cSBrian Somers } 9381e991daaSBrian Somers 9393a7b6d76SBrian Somers if (bundle->dev.header) { 94030949fd4SBrian Somers tun.header.family = htonl(af); 94170ee81ffSBrian Somers nb += sizeof tun - sizeof tun.data; 9423a7b6d76SBrian Somers data = (char *)&tun; 9433a7b6d76SBrian Somers } else 9443a7b6d76SBrian Somers data = tun.data; 9453a7b6d76SBrian Somers 9463a7b6d76SBrian Somers nw = write(bundle->dev.fd, data, nb); 947057f1760SBrian Somers if (nw != (ssize_t)nb) { 94857fd05c4SBrian Somers if (nw == -1) 9491814213eSMarcel Moolenaar log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %s\n", 95076d98538SBrian Somers l->name, nb, strerror(errno)); 95157fd05c4SBrian Somers else 9521814213eSMarcel Moolenaar log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %zd\n", l->name, nb, 9531814213eSMarcel Moolenaar nw); 9546db75539SBrian Somers } 9555d9e6103SBrian Somers 95630949fd4SBrian Somers return nb; 95730949fd4SBrian Somers } 95830949fd4SBrian Somers 95930949fd4SBrian Somers struct mbuf * 96030949fd4SBrian Somers ipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 96130949fd4SBrian Somers { 96230949fd4SBrian Somers int nb; 96330949fd4SBrian Somers 96430949fd4SBrian Somers if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 96530949fd4SBrian Somers log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n"); 96630949fd4SBrian Somers m_freem(bp); 9675d9e6103SBrian Somers return NULL; 968af57ed9fSAtsushi Murai } 969af57ed9fSAtsushi Murai 97030949fd4SBrian Somers m_settype(bp, MB_IPIN); 97130949fd4SBrian Somers 97230949fd4SBrian Somers nb = ip_Input(bundle, l, bp, AF_INET); 97330949fd4SBrian Somers ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 97430949fd4SBrian Somers 97530949fd4SBrian Somers return NULL; 97630949fd4SBrian Somers } 97730949fd4SBrian Somers 97830949fd4SBrian Somers #ifndef NOINET6 97930949fd4SBrian Somers struct mbuf * 98030949fd4SBrian Somers ipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 981af57ed9fSAtsushi Murai { 98230949fd4SBrian Somers int nb; 983af57ed9fSAtsushi Murai 9841136c6acSBrian Somers if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) { 98530949fd4SBrian Somers log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n"); 98630949fd4SBrian Somers m_freem(bp); 98730949fd4SBrian Somers return NULL; 988af57ed9fSAtsushi Murai } 989af57ed9fSAtsushi Murai 99030949fd4SBrian Somers m_settype(bp, MB_IPV6IN); 9916f8e9f0aSBrian Somers 99230949fd4SBrian Somers nb = ip_Input(bundle, l, bp, AF_INET6); 99330949fd4SBrian Somers ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb); 99430949fd4SBrian Somers 99530949fd4SBrian Somers return NULL; 9966f8e9f0aSBrian Somers } 99730949fd4SBrian Somers #endif 998