2 * Copyright (C) 1993-1998 by Darren Reed.
4 * Redistribution and use in source and binary forms are permitted
5 * provided that this notice is preserved and due credit is given
6 * to the original author and the contributors.
9 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed";
10 /*static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.4.2.16 2000/01/16 10:12:42 darrenr Exp $";*/
11 static const char rcsid[] = "@(#)$FreeBSD$";
15 #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
18 #if defined(KERNEL) && !defined(_KERNEL)
21 #include <sys/param.h>
22 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
24 # include "opt_ipfilter_log.h"
26 #if defined(__FreeBSD__) && !defined(__FreeBSD_version)
27 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
28 # include <sys/osreldate.h>
30 # include <osreldate.h>
40 #include <sys/errno.h>
41 #include <sys/types.h>
43 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
44 # include <sys/fcntl.h>
45 # include <sys/filio.h>
47 # include <sys/ioctl.h>
51 # include <sys/systm.h>
55 # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
56 # include <sys/dirent.h>
60 # include <sys/mbuf.h>
62 # include <sys/filio.h>
64 #include <sys/protosw.h>
65 #include <sys/socket.h>
71 #if __FreeBSD_version >= 300000
72 # include <net/if_var.h>
73 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
74 # include "opt_ipfilter.h"
78 #include <sys/debug.h>
79 # ifdef IFF_DRVRLOCK /* IRIX6 */
80 #include <sys/hashing.h>
83 #include <net/route.h>
84 #include <netinet/in.h>
85 #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */
86 # include <netinet/in_var.h>
88 #include <netinet/in_systm.h>
89 #include <netinet/ip.h>
90 #include <netinet/ip_var.h>
91 #include <netinet/tcp.h>
92 #include <netinet/udp.h>
93 #include <netinet/tcpip.h>
94 #include <netinet/ip_icmp.h>
99 #include "netinet/ip_compat.h"
100 #include "netinet/ip_fil.h"
101 #include "netinet/ip_proxy.h"
102 #include "netinet/ip_nat.h"
103 #include "netinet/ip_frag.h"
104 #include "netinet/ip_state.h"
105 #include "netinet/ip_auth.h"
106 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
107 # include <sys/malloc.h>
110 # define MIN(a,b) (((a)<(b))?(a):(b))
112 #if !SOLARIS && defined(_KERNEL) && !defined(__sgi)
113 # include <sys/kernel.h>
114 extern int ip_optcopy __P((struct ip *, struct ip *));
118 extern struct protosw inetsw[];
122 static struct ifnet **ifneta = NULL;
125 # if (BSD < 199306) || defined(__sgi)
130 int ipl_unreach = ICMP_UNREACH_FILTER;
131 u_long ipl_frouteok[2] = {0, 0};
133 static void frzerostats __P((caddr_t));
134 #if defined(__NetBSD__) || defined(__OpenBSD__)
135 static int frrequest __P((int, u_long, caddr_t, int));
137 static int frrequest __P((int, int, caddr_t, int));
140 static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
141 static int send_ip __P((struct mbuf *, ip_t *));
143 extern kmutex_t ipf_rw;
144 extern KRWLOCK_T ipf_mutex;
147 int ipllog __P((void));
148 void init_ifp __P((void));
150 static int no_output __P((struct ifnet *, struct mbuf *,
152 static int write_output __P((struct ifnet *, struct mbuf *,
155 static int no_output __P((struct ifnet *, struct mbuf *,
156 struct sockaddr *, struct rtentry *));
157 static int write_output __P((struct ifnet *, struct mbuf *,
158 struct sockaddr *, struct rtentry *));
163 #if (__FreeBSD_version >= 300000) && defined(_KERNEL)
164 struct callout_handle ipfr_slowtimer_ch;
167 #if (_BSDI_VERSION >= 199510) && defined(_KERNEL)
168 # include <sys/device.h>
169 # include <sys/conf.h>
171 struct cfdriver iplcd = {
172 NULL, "ipl", NULL, NULL, DV_DULL, 0
175 struct devsw iplsw = {
177 iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap,
178 nostrat, nodump, nopsize, 0,
181 #endif /* _BSDI_VERSION >= 199510 && _KERNEL */
183 #if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701)
184 # include <sys/conf.h>
185 # if defined(NETBSD_PF)
186 # include <net/pfil.h>
188 * We provide the fr_checkp name just to minimize changes later.
190 int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
191 # endif /* NETBSD_PF */
192 #endif /* __NetBSD__ */
195 # if defined(IPFILTER_LKM) && !defined(__sgi)
199 if (strcmp(s, "ipl") == 0)
203 # endif /* IPFILTER_LKM */
207 * Try to detect the case when compiling for NetBSD with pseudo-device
209 # if defined(__NetBSD__) && defined(PFIL_HOOKS)
211 ipfilterattach(count)
214 if (iplattach() != 0)
215 printf("IP Filter failed to attach\n");
229 if (fr_running || (fr_checkp == fr_check)) {
230 printf("IP Filter: already initialized\n");
238 if (nat_init() == -1)
240 if (fr_stateinit() == -1)
242 if (appr_init() == -1)
246 pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
250 error = ipfilter_sgi_attach();
257 bzero((char *)frcache, sizeof(frcache));
258 fr_savep = fr_checkp;
259 fr_checkp = fr_check;
262 if (fr_pass & FR_PASS)
264 else if (fr_pass & FR_BLOCK)
267 defpass = "no-match -> block";
269 printf("IP Filter: initialized. Default = %s all, Logging = %s\n",
276 printf("%s\n", ipfilter_version);
278 # if (__FreeBSD_version >= 300000) && defined(_KERNEL)
279 ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2);
281 timeout(ipfr_slowtimer, NULL, hz/2);
290 * Disable the filter by removing the hooks from the IP input/output
295 int s, i = FR_INQUE|FR_OUTQUE;
298 # if (__FreeBSD_version >= 300000)
299 untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch);
302 untimeout(ipfr_slowtimer);
304 untimeout(ipfr_slowtimer, NULL);
311 printf("IP Filter: not initialized\n");
316 fr_checkp = fr_savep;
317 i = frflush(IPL_LOGIPF, i);
321 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
325 ipfilter_sgi_detach();
339 static void frzerostats(data)
344 bcopy((char *)frstats, (char *)fio.f_st,
345 sizeof(struct filterstats) * 2);
346 fio.f_fin[0] = ipfilter[0][0];
347 fio.f_fin[1] = ipfilter[0][1];
348 fio.f_fout[0] = ipfilter[1][0];
349 fio.f_fout[1] = ipfilter[1][1];
350 fio.f_acctin[0] = ipacct[0][0];
351 fio.f_acctin[1] = ipacct[0][1];
352 fio.f_acctout[0] = ipacct[1][0];
353 fio.f_acctout[1] = ipacct[1][1];
354 fio.f_active = fr_active;
355 fio.f_froute[0] = ipl_frouteok[0];
356 fio.f_froute[1] = ipl_frouteok[1];
357 IWCOPY((caddr_t)&fio, data, sizeof(fio));
358 bzero((char *)frstats, sizeof(*frstats) * 2);
363 * Filter ioctl interface.
366 int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode
368 , cred_t *cp, int *rp
372 int IPL_EXTERN(ioctl)(dev, cmd, data, mode
373 #if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
374 (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
381 #if defined(__NetBSD__) || defined(__OpenBSD__) || \
382 (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000)
391 #if defined(_KERNEL) && !SOLARIS
394 int error = 0, unit = 0, tmp;
396 #if (BSD >= 199306) && defined(_KERNEL)
397 if ((securelevel >= 2) && (mode & FWRITE))
401 unit = GET_MINOR(dev);
402 if ((IPL_LOGMAX < unit) || (unit < 0))
410 if (unit == IPL_LOGNAT) {
413 error = nat_ioctl(data, cmd, mode);
417 if (unit == IPL_LOGSTATE) {
420 error = fr_state_ioctl(data, cmd, mode);
427 IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data,
428 sizeof(iplused[IPL_LOGIPF]));
431 #if !defined(IPFILTER_LKM) && defined(_KERNEL)
436 if (!(mode & FWRITE))
439 IRCOPY(data, (caddr_t)&enable, sizeof(enable));
449 if (!(mode & FWRITE))
452 IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags));
455 IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
461 if (!(mode & FWRITE))
464 error = frrequest(unit, cmd, data, fr_active);
469 if (!(mode & FWRITE))
472 error = frrequest(unit, cmd, data, 1 - fr_active);
475 if (!(mode & FWRITE))
478 bzero((char *)frcache, sizeof(frcache[0]) * 2);
479 *(u_int *)data = fr_active;
480 fr_active = 1 - fr_active;
487 bcopy((char *)frstats, (char *)fio.f_st,
488 sizeof(struct filterstats) * 2);
489 fio.f_fin[0] = ipfilter[0][0];
490 fio.f_fin[1] = ipfilter[0][1];
491 fio.f_fout[0] = ipfilter[1][0];
492 fio.f_fout[1] = ipfilter[1][1];
493 fio.f_acctin[0] = ipacct[0][0];
494 fio.f_acctin[1] = ipacct[0][1];
495 fio.f_acctout[0] = ipacct[1][0];
496 fio.f_acctout[1] = ipacct[1][1];
498 fio.f_active = fr_active;
499 fio.f_froute[0] = ipl_frouteok[0];
500 fio.f_froute[1] = ipl_frouteok[1];
501 fio.f_running = fr_running;
502 fio.f_groups[0][0] = ipfgroups[0][0];
503 fio.f_groups[0][1] = ipfgroups[0][1];
504 fio.f_groups[1][0] = ipfgroups[1][0];
505 fio.f_groups[1][1] = ipfgroups[1][1];
506 fio.f_groups[2][0] = ipfgroups[2][0];
507 fio.f_groups[2][1] = ipfgroups[2][1];
513 fio.f_defpass = fr_pass;
514 strncpy(fio.f_version, ipfilter_version,
515 sizeof(fio.f_version));
516 IWCOPY((caddr_t)&fio, data, sizeof(fio));
520 if (!(mode & FWRITE))
526 if (!(mode & FWRITE))
529 IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
530 tmp = frflush(unit, tmp);
531 IWCOPY((caddr_t)&tmp, data, sizeof(tmp));
536 if (!(mode & FWRITE))
539 *(int *)data = ipflog_clear(unit);
541 #endif /* IPFILTER_LOG */
543 IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t));
547 if (!(mode & FWRITE)) {
552 error = fr_auth_ioctl(data, cmd, NULL, NULL);
555 if (!(mode & FWRITE))
558 #if defined(_KERNEL) && defined(__sgi)
573 void fr_forgetifp(ifp)
576 register frentry_t *f;
578 WRITE_ENTER(&ipf_mutex);
579 for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
580 if (f->fr_ifa == ifp)
581 f->fr_ifa = (void *)-1;
582 for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
583 if (f->fr_ifa == ifp)
584 f->fr_ifa = (void *)-1;
585 for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
586 if (f->fr_ifa == ifp)
587 f->fr_ifa = (void *)-1;
588 for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
589 if (f->fr_ifa == ifp)
590 f->fr_ifa = (void *)-1;
591 RWLOCK_EXIT(&ipf_mutex);
596 static int frrequest(unit, req, data, set)
598 #if defined(__NetBSD__) || defined(__OpenBSD__)
606 register frentry_t *fp, *f, **fprev;
607 register frentry_t **ftail;
610 frgroup_t *fg = NULL;
615 IRCOPY(data, (caddr_t)fp, sizeof(*fp));
619 * Check that the group number does exist and that if a head group
620 * has been specified, doesn't exist.
622 if ((req != SIOCZRLST) && fp->fr_grhead &&
623 fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL))
625 if ((req != SIOCZRLST) && fp->fr_group &&
626 !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL))
629 in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
631 if (unit == IPL_LOGAUTH)
632 ftail = fprev = &ipauth;
633 else if (fp->fr_flags & FR_ACCOUNT)
634 ftail = fprev = &ipacct[in][set];
635 else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE))
636 ftail = fprev = &ipfilter[in][set];
640 if ((group = fp->fr_group)) {
641 if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL)))
643 ftail = fprev = fg->fg_start;
646 bzero((char *)frcache, sizeof(frcache[0]) * 2);
648 if (*fp->fr_ifname) {
649 fp->fr_ifa = GETUNIT(fp->fr_ifname);
651 fp->fr_ifa = (void *)-1;
654 if (*fp->fr_oifname) {
655 fp->fr_oifa = GETUNIT(fp->fr_oifname);
657 fp->fr_oifa = (void *)-1;
662 fp->fr_flags &= ~FR_DUP;
663 if (*fdp->fd_ifname) {
664 fdp->fd_ifp = GETUNIT(fdp->fd_ifname);
666 fdp->fd_ifp = (struct ifnet *)-1;
668 fp->fr_flags |= FR_DUP;
672 if (*fdp->fd_ifname) {
673 fdp->fd_ifp = GETUNIT(fdp->fd_ifname);
675 fdp->fd_ifp = (struct ifnet *)-1;
679 * Look for a matching filter rule, but don't include the next or
680 * interface pointer in the comparison (fr_next, fr_ifa).
682 for (; (f = *ftail); ftail = &f->fr_next)
683 if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip,
688 * If zero'ing statistics, copy current to caller and zero.
690 if (req == SIOCZRLST) {
693 IWCOPY((caddr_t)f, data, sizeof(*f));
700 if (req != SIOCINAFR && req != SIOCINIFR)
706 while (--fp->fr_hits && (f = *ftail))
713 if (req == SIOCDELFR || req == SIOCRMIFR) {
719 if (fg && fg->fg_head)
720 fg->fg_head->fr_ref--;
721 if (unit == IPL_LOGAUTH)
722 return fr_auth_ioctl(data, req, f, ftail);
724 fr_delgroup((u_int)f->fr_grhead, fp->fr_flags,
726 fixskip(fprev, f, -1);
734 if (unit == IPL_LOGAUTH)
735 return fr_auth_ioctl(data, req, fp, ftail);
736 KMALLOC(f, frentry_t *);
738 if (fg && fg->fg_head)
739 fg->fg_head->fr_ref++;
740 bcopy((char *)fp, (char *)f, sizeof(*f));
745 if (req == SIOCINIFR || req == SIOCINAFR)
746 fixskip(fprev, f, 1);
748 if ((group = f->fr_grhead))
749 fg = fr_addgroup(group, f, unit, set);
760 * routines below for saving IP headers to buffer
764 int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp)
766 int IPL_EXTERN(open)(dev_t dev, int flags)
769 int IPL_EXTERN(open)(dev, flags
770 # if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
771 (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
782 # if defined(__sgi) && defined(_KERNEL)
783 u_int min = geteminor(*pdev);
785 u_int min = GET_MINOR(dev);
788 if (IPL_LOGMAX < min)
797 int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp)
799 int IPL_EXTERN(close)(dev, flags
800 # if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
801 (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
812 u_int min = GET_MINOR(dev);
814 if (IPL_LOGMAX < min)
823 * both of these must operate with at least splnet() lest they be
824 * called during packet processing and cause an inconsistancy to appear in
828 int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp)
831 int IPL_EXTERN(read)(dev, uio, ioflag)
834 int IPL_EXTERN(read)(dev, uio)
837 register struct uio *uio;
841 return ipflog_read(GET_MINOR(dev), uio);
849 * send_reset - this could conceivably be a call to tcp_respond(), but that
850 * requires a large amount of setting up and isn't any more efficient.
852 int send_reset(fin, oip)
856 struct tcphdr *tcp, *tcp2;
862 tcp = (struct tcphdr *)fin->fin_dp;
863 if (tcp->th_flags & TH_RST)
864 return -1; /* feedback loop */
865 # if (BSD < 199306) || defined(__sgi)
866 m = m_get(M_DONTWAIT, MT_HEADER);
868 m = m_gethdr(M_DONTWAIT, MT_HEADER);
875 if (tcp->th_flags & TH_SYN)
877 m->m_len = sizeof(*tcp2) + sizeof(*ip);
879 m->m_data += max_linkhdr;
880 m->m_pkthdr.len = m->m_len;
881 m->m_pkthdr.rcvif = (struct ifnet *)0;
883 bzero(mtod(m, char *), sizeof(struct tcpiphdr));
884 ip = mtod(m, struct ip *);
885 tp = mtod(m, struct tcpiphdr *);
886 tcp2 = (struct tcphdr *)((char *)ip + sizeof(*ip));
888 ip->ip_src.s_addr = oip->ip_dst.s_addr;
889 ip->ip_dst.s_addr = oip->ip_src.s_addr;
890 tcp2->th_dport = tcp->th_sport;
891 tcp2->th_sport = tcp->th_dport;
892 tcp2->th_ack = ntohl(tcp->th_seq);
893 tcp2->th_ack += tlen;
894 tcp2->th_ack = htonl(tcp2->th_ack);
895 tcp2->th_off = sizeof(*tcp2) >> 2;
896 tcp2->th_flags = TH_RST|TH_ACK;
897 tp->ti_pr = oip->ip_p;
898 tp->ti_len = htons(sizeof(struct tcphdr));
899 tcp2->th_sum = in_cksum(m, sizeof(*ip) + sizeof(*tcp2));
901 ip->ip_tos = oip->ip_tos;
902 ip->ip_p = oip->ip_p;
903 ip->ip_len = sizeof(*ip) + sizeof(*tcp2);
905 return send_ip(m, ip);
909 static int send_ip(m, ip)
913 # if (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) || \
914 (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802))
918 # if (BSD < 199306) || defined(__sgi)
919 ip->ip_ttl = tcp_ttl;
921 ip->ip_ttl = ip_defttl;
925 m->m_pkthdr.rcvif = NULL;
927 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
931 bzero((char *)&ro, sizeof(ro));
932 err = ip_output(m, (struct mbuf *)0, &ro, 0, 0);
939 * extra 0 in case of multicast
941 # if _BSDI_VERSION >= 199802
942 return ip_output(m, (struct mbuf *)0, &ro, 0, 0, NULL);
944 # if defined(__OpenBSD__)
945 return ip_output(m, (struct mbuf *)0, 0, 0, 0, NULL);
947 return ip_output(m, (struct mbuf *)0, 0, 0, 0);
954 int send_icmp_err(oip, type, code, ifp, dst)
964 # if (BSD < 199306) || defined(__sgi)
965 m = m_get(M_DONTWAIT, MT_HEADER);
967 m = m_gethdr(M_DONTWAIT, MT_HEADER);
971 m->m_len = sizeof(*nip) + sizeof(*icmp) + 8;
973 m->m_data += max_linkhdr;
974 m->m_pkthdr.len = sizeof(*nip) + sizeof(*icmp) + 8;
975 m->m_pkthdr.rcvif = (struct ifnet *)0;
978 bzero(mtod(m, char *), (size_t)sizeof(*nip) + sizeof(*icmp) + 8);
979 nip = mtod(m, ip_t *);
980 icmp = (struct icmp *)(nip + 1);
982 nip->ip_v = IPVERSION;
983 nip->ip_hl = (sizeof(*nip) >> 2);
984 nip->ip_p = IPPROTO_ICMP;
985 nip->ip_id = oip->ip_id;
988 nip->ip_tos = oip->ip_tos;
989 nip->ip_len = sizeof(*nip) + sizeof(*icmp) + 8;
990 if (dst.s_addr == 0) {
991 if (fr_ifpaddr(ifp, &dst) == -1)
995 nip->ip_dst = oip->ip_src;
997 icmp->icmp_type = type;
998 icmp->icmp_code = code;
999 icmp->icmp_cksum = 0;
1000 bcopy((char *)oip, (char *)&icmp->icmp_ip, sizeof(*oip));
1001 bcopy((char *)oip + (oip->ip_hl << 2),
1002 (char *)&icmp->icmp_ip + sizeof(*oip), 8); /* 64 bits */
1005 register u_short __iplen, __ipoff;
1006 ip_t *ip = &icmp->icmp_ip;
1008 __iplen = ip->ip_len;
1009 __ipoff = ip->ip_off;
1010 ip->ip_len = htons(__iplen);
1011 ip->ip_off = htons(__ipoff);
1014 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, sizeof(*icmp) + 8);
1015 return send_ip(m, nip);
1019 # if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) && !defined(__sgi)
1021 int iplinit __P((void));
1025 void iplinit __P((void));
1031 if (iplattach() != 0)
1032 printf("IP Filter failed to attach\n");
1035 # endif /* ! __NetBSD__ */
1038 size_t mbufchainlen(m0)
1039 register struct mbuf *m0;
1041 register size_t len = 0;
1043 for (; m0; m0 = m0->m_next)
1049 int ipfr_fastroute(m0, fin, fdp)
1054 register struct ip *ip, *mhip;
1055 register struct mbuf *m = m0;
1056 register struct route *ro;
1057 int len, off, error = 0, hlen;
1058 struct sockaddr_in *dst;
1059 struct route iproute;
1063 hlen = fin->fin_hlen;
1064 ip = mtod(m0, struct ip *);
1069 bzero((caddr_t)ro, sizeof (*ro));
1070 dst = (struct sockaddr_in *)&ro->ro_dst;
1071 dst->sin_family = AF_INET;
1076 * In case we're here due to "to <if>" being used with "keep state",
1077 * check that we're going in the correct direction.
1079 if ((fr != NULL) && (fin->fin_rev != 0)) {
1080 if ((ifp != NULL) && (fdp == &fr->fr_tif))
1082 dst->sin_addr = ip->ip_dst;
1084 dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst;
1086 dst->sin_len = sizeof(*dst);
1088 # if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
1089 !defined(__OpenBSD__)
1091 rtalloc_ign(ro, RTF_CLONING);
1093 rtalloc_ign(ro, RTF_PRCLONING);
1099 if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) {
1103 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
1104 if (in_localaddr(ip->ip_dst))
1105 error = EHOSTUNREACH;
1107 error = ENETUNREACH;
1110 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
1111 dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
1114 ro->ro_rt->rt_use++;
1117 * For input packets which are being "fastrouted", they won't
1118 * go back through output filtering and miss their chance to get
1119 * NAT'd and counted.
1122 if (fin->fin_out == 0) {
1124 if ((fin->fin_fr = ipacct[1][fr_active]) &&
1125 (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
1126 ATOMIC_INC(frstats[1].fr_acct);
1129 (void) fr_checkstate(ip, fin);
1130 (void) ip_natout(ip, fin);
1134 * If small enough for interface, can just send directly.
1136 if (ip->ip_len <= ifp->if_mtu) {
1138 ip->ip_id = htons(ip->ip_id);
1139 ip->ip_len = htons(ip->ip_len);
1140 ip->ip_off = htons(ip->ip_off);
1143 ip->ip_sum = in_cksum(m, hlen);
1145 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1148 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
1153 * Too large for interface; fragment if possible.
1154 * Must be able to put at least 8 bytes per fragment.
1156 if (ip->ip_off & IP_DF) {
1160 len = (ifp->if_mtu - hlen) &~ 7;
1167 int mhlen, firstlen = len;
1168 struct mbuf **mnext = &m->m_act;
1171 * Loop through length of segment after first fragment,
1172 * make new header and copy data of each part and link onto chain.
1175 mhlen = sizeof (struct ip);
1176 for (off = hlen + len; off < ip->ip_len; off += len) {
1178 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1180 MGET(m, M_DONTWAIT, MT_HEADER);
1187 m->m_data += max_linkhdr;
1189 m->m_off = MMAXOFF - hlen;
1191 mhip = mtod(m, struct ip *);
1192 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1193 if (hlen > sizeof (struct ip)) {
1194 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1195 mhip->ip_hl = mhlen >> 2;
1198 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
1199 if (ip->ip_off & IP_MF)
1200 mhip->ip_off |= IP_MF;
1201 if (off + len >= ip->ip_len)
1202 len = ip->ip_len - off;
1204 mhip->ip_off |= IP_MF;
1205 mhip->ip_len = htons((u_short)(len + mhlen));
1206 m->m_next = m_copy(m0, off, len);
1207 if (m->m_next == 0) {
1208 error = ENOBUFS; /* ??? */
1212 m->m_pkthdr.len = mhlen + len;
1213 m->m_pkthdr.rcvif = NULL;
1216 mhip->ip_off = htons((u_short)mhip->ip_off);
1219 mhip->ip_sum = in_cksum(m, mhlen);
1224 * Update first fragment by trimming what's been copied out
1225 * and updating header, then send each fragment (in order).
1227 m_adj(m0, hlen + firstlen - ip->ip_len);
1228 ip->ip_len = htons((u_short)(hlen + firstlen));
1229 ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1231 ip->ip_sum = in_cksum(m0, hlen);
1233 for (m = m0; m; m = m0) {
1238 error = (*ifp->if_output)(ifp, m,
1239 (struct sockaddr *)dst, ro->ro_rt);
1241 error = (*ifp->if_output)(ifp, m,
1242 (struct sockaddr *)dst);
1258 if (error == EMSGSIZE)
1259 (void) send_icmp_err(ip, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
1264 #else /* #ifdef _KERNEL */
1268 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1269 struct sockaddr *s))
1271 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1272 struct sockaddr *s, struct rtentry *rt))
1281 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1282 struct sockaddr *s))
1284 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1285 struct sockaddr *s, struct rtentry *rt))
1288 ip_t *ip = (ip_t *)m;
1290 static int write_output(ifp, ip)
1298 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1299 (defined(OpenBSD) && (OpenBSD >= 199603))
1300 sprintf(fname, "/tmp/%s", ifp->if_xname);
1302 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
1304 fd = open(fname, O_WRONLY|O_APPEND);
1309 write(fd, (char *)ip, ntohs(ip->ip_len));
1315 struct ifnet *get_unit(name)
1318 struct ifnet *ifp, **ifa;
1319 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1320 (defined(OpenBSD) && (OpenBSD >= 199603))
1321 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1322 if (!strcmp(name, ifp->if_xname))
1326 char ifname[32], *s;
1328 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1329 (void) sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
1330 if (!strcmp(name, ifname))
1336 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
1338 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
1342 ifneta = (struct ifnet **)realloc(ifneta,
1343 (nifs + 1) * sizeof(*ifa));
1344 ifneta[nifs] = NULL;
1345 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
1347 ifp = ifneta[nifs - 1];
1349 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1350 (defined(OpenBSD) && (OpenBSD >= 199603))
1351 strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
1353 for (s = name; *s && !isdigit(*s); s++)
1355 if (*s && isdigit(*s)) {
1356 ifp->if_unit = atoi(s);
1357 ifp->if_name = (char *)malloc(s - name + 1);
1358 strncpy(ifp->if_name, name, s - name);
1359 ifp->if_name[s - name] = '\0';
1361 ifp->if_name = strdup(name);
1365 ifp->if_output = no_output;
1373 struct ifnet *ifp, **ifa;
1377 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1378 (defined(OpenBSD) && (OpenBSD >= 199603))
1379 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1380 ifp->if_output = write_output;
1381 sprintf(fname, "/tmp/%s", ifp->if_xname);
1382 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
1390 for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
1391 ifp->if_output = write_output;
1392 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
1393 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
1403 int ipfr_fastroute(ip, fin, fdp)
1408 struct ifnet *ifp = fdp->fd_ifp;
1411 return 0; /* no routing table out here */
1413 ip->ip_len = htons((u_short)ip->ip_len);
1414 ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1417 (*ifp->if_output)(ifp, (void *)ip, NULL);
1419 (*ifp->if_output)(ifp, (void *)ip, NULL, 0);
1425 int ipllog __P((void))
1432 int send_reset(ip, ifp)
1436 verbose("- TCP RST sent\n");
1441 int icmp_error(ip, ifp)
1445 verbose("- TCP RST sent\n");
1454 #endif /* _KERNEL */