4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
11 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
12 static const char rcsid[] = "@(#)$Id$";
19 ipf_main_softc_t ipfmain;
21 static struct ifnet **ifneta = NULL;
26 static void ipf_setifpaddr __P((struct ifnet *, char *));
27 void init_ifp __P((void));
28 #if defined(__sgi) && (IRIX < 60500)
29 static int no_output __P((struct ifnet *, struct mbuf *,
31 static int write_output __P((struct ifnet *, struct mbuf *,
35 static int no_output __P((struct ifnet *, struct mbuf *,
36 struct sockaddr *, struct rtentry *, char *));
37 static int write_output __P((struct ifnet *, struct mbuf *,
38 struct sockaddr *, struct rtentry *, char *));
40 static int no_output __P((struct ifnet *, struct mbuf *,
41 struct sockaddr *, struct rtentry *));
42 static int write_output __P((struct ifnet *, struct mbuf *,
43 struct sockaddr *, struct rtentry *));
50 ipf_main_softc_t *softc;
58 ipf_main_softc_t *softc;
65 * Filter ioctl interface.
68 ipfioctl(softc, dev, cmd, data, mode)
69 ipf_main_softc_t *softc;
75 int error = 0, unit = 0, uid;
82 error = ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, NULL);
93 ipf_forgetifp(softc, ifp)
94 ipf_main_softc_t *softc;
97 register frentry_t *f;
99 WRITE_ENTER(&softc->ipf_mutex);
100 for (f = softc->ipf_acct[0][softc->ipf_active]; (f != NULL);
102 if (f->fr_ifa == ifp)
103 f->fr_ifa = (void *)-1;
104 for (f = softc->ipf_acct[1][softc->ipf_active]; (f != NULL);
106 if (f->fr_ifa == ifp)
107 f->fr_ifa = (void *)-1;
108 for (f = softc->ipf_rules[0][softc->ipf_active]; (f != NULL);
110 if (f->fr_ifa == ifp)
111 f->fr_ifa = (void *)-1;
112 for (f = softc->ipf_rules[1][softc->ipf_active]; (f != NULL);
114 if (f->fr_ifa == ifp)
115 f->fr_ifa = (void *)-1;
116 RWLOCK_EXIT(&softc->ipf_mutex);
117 ipf_nat_sync(softc, ifp);
118 ipf_lookup_sync(softc, ifp);
123 #if defined(__sgi) && (IRIX < 60500)
127 no_output (ifp, m, s, rt, cp)
130 no_output(ifp, m, s, rt)
143 #if defined(__sgi) && (IRIX < 60500)
144 write_output(ifp, m, s)
147 write_output (ifp, m, s, rt, cp)
150 write_output(ifp, m, s, rt)
164 ip = MTOD(mb, ip_t *);
166 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
167 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
168 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
169 sprintf(fname, "/tmp/%s", ifp->if_xname);
171 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
173 fd = open(fname, O_WRONLY|O_APPEND);
178 write(fd, (char *)ip, ntohs(ip->ip_len));
185 ipf_setifpaddr(ifp, addr)
190 struct in_ifaddr *ifa;
195 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
196 if (ifp->if_addrlist.tqh_first != NULL)
199 if (ifp->in_ifaddr != NULL)
201 if (ifp->if_addrlist != NULL)
206 ifa = (struct ifaddr *)malloc(sizeof(*ifa));
207 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
208 ifp->if_addrlist.tqh_first = ifa;
211 ifp->in_ifaddr = ifa;
213 ifp->if_addrlist = ifa;
218 struct sockaddr_in *sin;
221 sin = (struct sockaddr_in *)&ifa->ia_addr;
223 sin = (struct sockaddr_in *)&ifa->ifa_addr;
226 if (index(addr, ':') != NULL) {
227 struct sockaddr_in6 *sin6;
229 sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
230 sin6->sin6_family = AF_INET6;
231 /* Abort if bad address. */
232 switch (inet_pton(AF_INET6, addr, &sin6->sin6_addr))
247 sin->sin_family = AF_INET;
248 sin->sin_addr.s_addr = inet_addr(addr);
249 if (sin->sin_addr.s_addr == 0)
256 get_unit(name, family)
260 struct ifnet *ifp, **ifpp, **old_ifneta;
262 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
263 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
264 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
272 addr = strchr(name, '=');
276 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
277 if (!strcmp(name, ifp->if_xname)) {
279 ipf_setifpaddr(ifp, addr);
284 char *s, ifname[LIFNAMSIZ+1];
289 addr = strchr(name, '=');
293 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
294 COPYIFNAME(family, ifp, ifname);
295 if (!strcmp(name, ifname)) {
297 ipf_setifpaddr(ifp, addr);
304 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
308 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
317 ifneta = (struct ifnet **)realloc(ifneta,
318 (nifs + 1) * sizeof(ifp));
325 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
326 if (!ifneta[nifs - 1]) {
331 ifp = ifneta[nifs - 1];
333 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
334 TAILQ_INIT(&ifp->if_addrlist);
336 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
337 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
338 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
339 (void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
341 s = name + strlen(name) - 1;
342 for (; s > name; s--) {
349 if ((s > name) && (*s != 0) && ISDIGIT(*s)) {
350 ifp->if_unit = atoi(s);
351 ifp->if_name = (char *)malloc(s - name + 1);
352 (void) strncpy(ifp->if_name, name, s - name);
353 ifp->if_name[s - name] = '\0';
355 ifp->if_name = strdup(name);
359 ifp->if_output = (void *)no_output;
362 ipf_setifpaddr(ifp, addr);
373 static char ifname[LIFNAMSIZ];
375 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
376 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
377 sprintf(ifname, "%s", ifp->if_xname);
379 if (ifp->if_unit != -1)
380 sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
382 strcpy(ifname, ifp->if_name);
392 struct ifnet *ifp, **ifpp;
396 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
397 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
398 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
399 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
400 ifp->if_output = (void *)write_output;
401 sprintf(fname, "/tmp/%s", ifp->if_xname);
402 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
410 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
411 ifp->if_output = (void *)write_output;
412 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
413 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
424 ipf_fastroute(m, mpp, fin, fdp)
430 ip_t *ip = fin->fin_ip;
442 if (!(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
443 (fdp->fd_type == FRD_DSTLIST)) {
444 bzero(&node, sizeof(node));
445 ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node);
451 return 0; /* no routing table out here */
453 if (fin->fin_out == 0) {
456 (void) ipf_acctpkt(fin, NULL);
458 if (!fr || !(fr->fr_flags & FR_RETMASK)) {
461 (void) ipf_state_check(fin, &pass);
464 switch (ipf_nat_checkout(fin, NULL))
480 printpacket(fin->fin_out, m);
482 #if defined(__sgi) && (IRIX < 60500)
483 (*ifp->if_output)(ifp, (void *)ip, NULL);
485 (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
487 (*ifp->if_output)(ifp, (void *)m, NULL, 0);
501 ipfkverbose("- TCP RST sent\n");
507 ipf_send_icmp_err(type, fin, dst)
512 ipfkverbose("- ICMP unreachable sent\n");
526 m_copydata(m, off, len, cp)
531 bcopy((char *)m + off, cp, len);
536 ipfuiomove(buf, len, rwflag, uio)
541 int left, ioc, num, offset;
545 if (rwflag == UIO_READ) {
549 offset = uio->uio_offset;
551 while ((left > 0) && (ioc < uio->uio_iovcnt)) {
552 io = uio->uio_iov + ioc;
556 start = (char *)io->iov_base + offset;
557 if (start > (char *)io->iov_base + io->iov_len) {
558 offset -= io->iov_len;
562 bcopy(buf, start, num);
563 uio->uio_resid -= num;
564 uio->uio_offset += num;
580 static int iss_seq_off = 0;
586 * Compute the base value of the ISS. It is a hash
587 * of (saddr, sport, daddr, dport, secret).
591 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
592 sizeof(fin->fin_fi.fi_src));
593 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
594 sizeof(fin->fin_fi.fi_dst));
595 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
597 /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
599 MD5Final(hash, &ctx);
601 memcpy(&newiss, hash, sizeof(newiss));
604 * Now increment our "timer", and add it in to
605 * the computed value.
608 * XXX TCP_ISSINCR too large to use?
610 iss_seq_off += 0x00010000;
611 newiss += iss_seq_off;
616 /* ------------------------------------------------------------------------ */
617 /* Function: ipf_nextipid */
618 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */
619 /* Parameters: fin(I) - pointer to packet information */
621 /* Returns the next IPv4 ID to use for this packet. */
622 /* ------------------------------------------------------------------------ */
627 static u_short ipid = 0;
628 ipf_main_softc_t *softc = fin->fin_main_soft;
631 MUTEX_ENTER(&softc->ipf_rw);
632 if (fin->fin_pktnum != 0) {
634 * The -1 is for aligned test results.
636 id = (fin->fin_pktnum - 1) & 0xffff;
640 MUTEX_EXIT(&softc->ipf_rw);
651 if (fin->fin_flx & FI_SHORT)
654 if (ipf_checkl4sum(fin) == -1) {
655 fin->fin_flx |= FI_BAD;
667 if (fin->fin_flx & FI_SHORT)
670 if (ipf_checkl4sum(fin) == -1) {
671 fin->fin_flx |= FI_BAD;
681 * See above for description, except that all addressing is in user space.
684 copyoutptr(softc, src, dst, size)
690 bcopy(dst, (char *)&ca, sizeof(ca));
691 bcopy(src, ca, size);
697 * See above for description, except that all addressing is in user space.
700 copyinptr(src, dst, size)
706 bcopy(src, (char *)&ca, sizeof(ca));
707 bcopy(ca, dst, size);
714 * return the first IP Address associated with an interface
717 ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
718 ipf_main_softc_t *softc;
721 i6addr_t *inp, *inpmask;
723 struct ifnet *ifp = ifptr;
725 struct in_ifaddr *ifa;
730 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
731 ifa = ifp->if_addrlist.tqh_first;
734 ifa = (struct in_ifaddr *)ifp->in_ifaddr;
736 ifa = ifp->if_addrlist;
741 struct sockaddr_in *sin, mask;
743 mask.sin_addr.s_addr = 0xffffffff;
746 sin = (struct sockaddr_in *)&ifa->ia_addr;
748 sin = (struct sockaddr_in *)&ifa->ifa_addr;
751 return ipf_ifpfillv4addr(atype, sin, &mask,
752 &inp->in4, &inpmask->in4);
756 struct sockaddr_in6 *sin6, mask;
758 sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
759 ((i6addr_t *)&mask.sin6_addr)->i6[0] = 0xffffffff;
760 ((i6addr_t *)&mask.sin6_addr)->i6[1] = 0xffffffff;
761 ((i6addr_t *)&mask.sin6_addr)->i6[2] = 0xffffffff;
762 ((i6addr_t *)&mask.sin6_addr)->i6[3] = 0xffffffff;
763 return ipf_ifpfillv6addr(atype, sin6, &mask,
773 * This function is not meant to be random, rather just produce a
774 * sequence of numbers that isn't linear to show "randomness".
779 static unsigned int last = 0xa5a5a5a5;
780 static int calls = 0;
786 * These are deliberately chosen to ensure that there is some
787 * attempt to test whether the output covers the range in test n18.
840 ipf_pcksum(fin, hlen, sum)
849 slen = fin->fin_plen - hlen;
850 sp = (u_short *)((u_char *)fin->fin_ip + hlen);
852 for (; slen > 1; slen -= 2)
855 sum += ntohs(*(u_char *)sp << 8);
857 sum = (sum & 0xffff) + (sum >> 16);
858 sum2 = (u_short)(~sum & 0xffff);
865 ipf_pullup(m, fin, plen)
870 if (M_LEN(m) >= plen)
874 * Fake ipf_pullup failing
876 fin->fin_reason = FRB_PULLUP;