1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-28 08:02:54 +00:00
freebsd/sbin/ipf/ipftest/ip_fil.c
Warner Losh 51e16cb8fc sbin: Remove ancient SCCS tags.
Remove ancient SCCS tags from the tree, automated scripting, with two
minor fixup to keep things compiling. All the common forms in the tree
were removed with a perl script.

Sponsored by:		Netflix
2023-11-26 22:23:29 -07:00

808 lines
14 KiB
C

/*
* Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* $Id$
*/
#include "ipf.h"
#include "md5.h"
#include "ipt.h"
ipf_main_softc_t ipfmain;
static struct ifnet **ifneta = NULL;
static int nifs = 0;
struct rtentry;
static void ipf_setifpaddr(struct ifnet *, char *);
void init_ifp(void);
static int no_output(struct ifnet *, struct mbuf *,
struct sockaddr *, struct rtentry *);
static int write_output(struct ifnet *, struct mbuf *,
struct sockaddr *, struct rtentry *);
struct ifaddr {
struct sockaddr_storage ifa_addr;
};
int
ipfattach(softc)
ipf_main_softc_t *softc;
{
return (0);
}
int
ipfdetach(softc)
ipf_main_softc_t *softc;
{
return (0);
}
/*
* Filter ioctl interface.
*/
int
ipfioctl(softc, dev, cmd, data, mode)
ipf_main_softc_t *softc;
int dev;
ioctlcmd_t cmd;
caddr_t data;
int mode;
{
int error = 0, unit = 0, uid;
uid = getuid();
unit = dev;
SPL_NET(s);
error = ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, NULL);
if (error != -1) {
SPL_X(s);
return (error);
}
SPL_X(s);
return (error);
}
void
ipf_forgetifp(softc, ifp)
ipf_main_softc_t *softc;
void *ifp;
{
register frentry_t *f;
WRITE_ENTER(&softc->ipf_mutex);
for (f = softc->ipf_acct[0][softc->ipf_active]; (f != NULL);
f = f->fr_next)
if (f->fr_ifa == ifp)
f->fr_ifa = (void *)-1;
for (f = softc->ipf_acct[1][softc->ipf_active]; (f != NULL);
f = f->fr_next)
if (f->fr_ifa == ifp)
f->fr_ifa = (void *)-1;
for (f = softc->ipf_rules[0][softc->ipf_active]; (f != NULL);
f = f->fr_next)
if (f->fr_ifa == ifp)
f->fr_ifa = (void *)-1;
for (f = softc->ipf_rules[1][softc->ipf_active]; (f != NULL);
f = f->fr_next)
if (f->fr_ifa == ifp)
f->fr_ifa = (void *)-1;
RWLOCK_EXIT(&softc->ipf_mutex);
ipf_nat_sync(softc, ifp);
ipf_lookup_sync(softc, ifp);
}
static int
no_output(ifp, m, s, rt)
struct rtentry *rt;
struct ifnet *ifp;
struct mbuf *m;
struct sockaddr *s;
{
return (0);
}
static int
write_output(ifp, m, s, rt)
struct rtentry *rt;
struct ifnet *ifp;
struct mbuf *m;
struct sockaddr *s;
{
char fname[32];
mb_t *mb;
ip_t *ip;
int fd;
mb = (mb_t *)m;
ip = MTOD(mb, ip_t *);
#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
defined(__FreeBSD__)
sprintf(fname, "/tmp/%s", ifp->if_xname);
#else
sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
#endif
fd = open(fname, O_WRONLY|O_APPEND);
if (fd == -1) {
perror("open");
return (-1);
}
write(fd, (char *)ip, ntohs(ip->ip_len));
close(fd);
return (0);
}
static void
ipf_setifpaddr(ifp, addr)
struct ifnet *ifp;
char *addr;
{
struct ifaddr *ifa;
#if defined(__NetBSD__) || defined(__FreeBSD__)
if (ifp->if_addrlist.tqh_first != NULL)
#else
if (ifp->if_addrlist != NULL)
#endif
return;
ifa = (struct ifaddr *)malloc(sizeof(*ifa));
#if defined(__NetBSD__) || defined(__FreeBSD__)
ifp->if_addrlist.tqh_first = ifa;
#else
ifp->if_addrlist = ifa;
#endif
if (ifa != NULL) {
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)&ifa->ifa_addr;
#ifdef USE_INET6
if (index(addr, ':') != NULL) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
sin6->sin6_family = AF_INET6;
/* Abort if bad address. */
switch (inet_pton(AF_INET6, addr, &sin6->sin6_addr))
{
case 1:
break;
case -1:
perror("inet_pton");
abort();
break;
default:
abort();
break;
}
} else
#endif
{
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr(addr);
if (sin->sin_addr.s_addr == 0)
abort();
}
}
}
struct ifnet *
get_unit(name, family)
char *name;
int family;
{
struct ifnet *ifp, **ifpp, **old_ifneta;
char *addr;
#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
defined(__FreeBSD__)
if (!*name)
return (NULL);
if (name == NULL)
name = "anon0";
addr = strchr(name, '=');
if (addr != NULL)
*addr++ = '\0';
for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
if (!strcmp(name, ifp->if_xname)) {
if (addr != NULL)
ipf_setifpaddr(ifp, addr);
return (ifp);
}
}
#else
char *s, ifname[LIFNAMSIZ+1];
if (name == NULL)
name = "anon0";
addr = strchr(name, '=');
if (addr != NULL)
*addr++ = '\0';
for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
COPYIFNAME(family, ifp, ifname);
if (!strcmp(name, ifname)) {
if (addr != NULL)
ipf_setifpaddr(ifp, addr);
return (ifp);
}
}
#endif
if (!ifneta) {
ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
if (!ifneta)
return (NULL);
ifneta[1] = NULL;
ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
if (!ifneta[0]) {
free(ifneta);
return (NULL);
}
nifs = 1;
} else {
old_ifneta = ifneta;
nifs++;
ifneta = (struct ifnet **)reallocarray(ifneta, nifs + 1,
sizeof(ifp));
if (!ifneta) {
free(old_ifneta);
nifs = 0;
return (NULL);
}
ifneta[nifs] = NULL;
ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
if (!ifneta[nifs - 1]) {
nifs--;
return (NULL);
}
}
ifp = ifneta[nifs - 1];
#if defined(__NetBSD__) || defined(__FreeBSD__)
TAILQ_INIT(&ifp->if_addrlist);
#endif
#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
defined(__FreeBSD__)
(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
#else
s = name + strlen(name) - 1;
for (; s > name; s--) {
if (!ISDIGIT(*s)) {
s++;
break;
}
}
if ((s > name) && (*s != 0) && ISDIGIT(*s)) {
ifp->if_unit = atoi(s);
ifp->if_name = (char *)malloc(s - name + 1);
(void) strncpy(ifp->if_name, name, s - name);
ifp->if_name[s - name] = '\0';
} else {
ifp->if_name = strdup(name);
ifp->if_unit = -1;
}
#endif
ifp->if_output = (void *)no_output;
if (addr != NULL) {
ipf_setifpaddr(ifp, addr);
}
return (ifp);
}
char *
get_ifname(ifp)
struct ifnet *ifp;
{
static char ifname[LIFNAMSIZ];
#if defined(__NetBSD__) || defined(__FreeBSD__)
sprintf(ifname, "%s", ifp->if_xname);
#else
if (ifp->if_unit != -1)
sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
else
strcpy(ifname, ifp->if_name);
#endif
return (ifname);
}
void
init_ifp()
{
struct ifnet *ifp, **ifpp;
char fname[32];
int fd;
#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
defined(__FreeBSD__)
for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
ifp->if_output = (void *)write_output;
sprintf(fname, "/tmp/%s", ifp->if_xname);
fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
if (fd == -1)
perror("open");
else
close(fd);
}
#else
for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
ifp->if_output = (void *)write_output;
sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
if (fd == -1)
perror("open");
else
close(fd);
}
#endif
}
int
ipf_fastroute(m, mpp, fin, fdp)
mb_t *m, **mpp;
fr_info_t *fin;
frdest_t *fdp;
{
struct ifnet *ifp;
ip_t *ip = fin->fin_ip;
frdest_t node;
int error = 0;
frentry_t *fr;
void *sifp;
int sout;
sifp = fin->fin_ifp;
sout = fin->fin_out;
fr = fin->fin_fr;
ip->ip_sum = 0;
if (!(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
(fdp->fd_type == FRD_DSTLIST)) {
bzero(&node, sizeof(node));
ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node);
fdp = &node;
}
ifp = fdp->fd_ptr;
if (ifp == NULL)
return (0; /* no routing table out here */);
if (fin->fin_out == 0) {
fin->fin_ifp = ifp;
fin->fin_out = 1;
(void) ipf_acctpkt(fin, NULL);
fin->fin_fr = NULL;
if (!fr || !(fr->fr_flags & FR_RETMASK)) {
u_32_t pass;
(void) ipf_state_check(fin, &pass);
}
switch (ipf_nat_checkout(fin, NULL))
{
case 0 :
break;
case 1 :
ip->ip_sum = 0;
break;
case -1 :
error = -1;
goto done;
break;
}
}
m->mb_ifp = ifp;
printpacket(fin->fin_out, m);
(*ifp->if_output)(ifp, (void *)m, NULL, 0);
done:
fin->fin_ifp = sifp;
fin->fin_out = sout;
return (error);
}
int
ipf_send_reset(fin)
fr_info_t *fin;
{
ipfkverbose("- TCP RST sent\n");
return (0);
}
int
ipf_send_icmp_err(type, fin, dst)
int type;
fr_info_t *fin;
int dst;
{
ipfkverbose("- ICMP unreachable sent\n");
return (0);
}
void
m_freem(m)
mb_t *m;
{
return;
}
void
m_copydata(m, off, len, cp)
mb_t *m;
int off, len;
caddr_t cp;
{
bcopy((char *)m + off, cp, len);
}
int
ipfuiomove(buf, len, rwflag, uio)
caddr_t buf;
int len, rwflag;
struct uio *uio;
{
int left, ioc, num, offset;
struct iovec *io;
char *start;
if (rwflag == UIO_READ) {
left = len;
ioc = 0;
offset = uio->uio_offset;
while ((left > 0) && (ioc < uio->uio_iovcnt)) {
io = uio->uio_iov + ioc;
num = io->iov_len;
if (num > left)
num = left;
start = (char *)io->iov_base + offset;
if (start > (char *)io->iov_base + io->iov_len) {
offset -= io->iov_len;
ioc++;
continue;
}
bcopy(buf, start, num);
uio->uio_resid -= num;
uio->uio_offset += num;
left -= num;
if (left > 0)
ioc++;
}
if (left > 0)
return (EFAULT);
}
return (0);
}
u_32_t
ipf_newisn(fin)
fr_info_t *fin;
{
static int iss_seq_off = 0;
u_char hash[16];
u_32_t newiss;
MD5_CTX ctx;
/*
* Compute the base value of the ISS. It is a hash
* of (saddr, sport, daddr, dport, secret).
*/
MD5Init(&ctx);
MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
sizeof(fin->fin_fi.fi_src));
MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
sizeof(fin->fin_fi.fi_dst));
MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
MD5Final(hash, &ctx);
memcpy(&newiss, hash, sizeof(newiss));
/*
* Now increment our "timer", and add it in to
* the computed value.
*
* XXX Use `addin'?
* XXX TCP_ISSINCR too large to use?
*/
iss_seq_off += 0x00010000;
newiss += iss_seq_off;
return (newiss);
}
/* ------------------------------------------------------------------------ */
/* Function: ipf_nextipid */
/* Returns: int - 0 == success, -1 == error (packet should be dropped) */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Returns the next IPv4 ID to use for this packet. */
/* ------------------------------------------------------------------------ */
inline u_short
ipf_nextipid(fin)
fr_info_t *fin;
{
static u_short ipid = 0;
ipf_main_softc_t *softc = fin->fin_main_soft;
u_short id;
MUTEX_ENTER(&softc->ipf_rw);
if (fin->fin_pktnum != 0) {
/*
* The -1 is for aligned test results.
*/
id = (fin->fin_pktnum - 1) & 0xffff;
} else {
}
id = ipid++;
MUTEX_EXIT(&softc->ipf_rw);
return (id);
}
inline int
ipf_checkv4sum(fin)
fr_info_t *fin;
{
if (fin->fin_flx & FI_SHORT)
return (1);
if (ipf_checkl4sum(fin) == -1) {
fin->fin_flx |= FI_BAD;
return (-1);
}
return (0);
}
#ifdef USE_INET6
inline int
ipf_checkv6sum(fin)
fr_info_t *fin;
{
if (fin->fin_flx & FI_SHORT)
return (1);
if (ipf_checkl4sum(fin) == -1) {
fin->fin_flx |= FI_BAD;
return (-1);
}
return (0);
}
#endif
#if 0
/*
* See above for description, except that all addressing is in user space.
*/
int
copyoutptr(softc, src, dst, size)
void *src, *dst;
size_t size;
{
caddr_t ca;
bcopy(dst, (char *)&ca, sizeof(ca));
bcopy(src, ca, size);
return (0);
}
/*
* See above for description, except that all addressing is in user space.
*/
int
copyinptr(src, dst, size)
void *src, *dst;
size_t size;
{
caddr_t ca;
bcopy(src, (char *)&ca, sizeof(ca));
bcopy(ca, dst, size);
return (0);
}
#endif
/*
* return the first IP Address associated with an interface
*/
int
ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
ipf_main_softc_t *softc;
int v, atype;
void *ifptr;
i6addr_t *inp, *inpmask;
{
struct ifnet *ifp = ifptr;
struct ifaddr *ifa;
#if defined(__NetBSD__) || defined(__FreeBSD__)
ifa = ifp->if_addrlist.tqh_first;
#else
ifa = ifp->if_addrlist;
#endif
if (ifa != NULL) {
if (v == 4) {
struct sockaddr_in *sin, mask;
mask.sin_addr.s_addr = 0xffffffff;
sin = (struct sockaddr_in *)&ifa->ifa_addr;
return (ipf_ifpfillv4addr(atype, sin, &mask,
&inp->in4, &inpmask->in4));
}
#ifdef USE_INET6
if (v == 6) {
struct sockaddr_in6 *sin6, mask;
sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
((i6addr_t *)&mask.sin6_addr)->i6[0] = 0xffffffff;
((i6addr_t *)&mask.sin6_addr)->i6[1] = 0xffffffff;
((i6addr_t *)&mask.sin6_addr)->i6[2] = 0xffffffff;
((i6addr_t *)&mask.sin6_addr)->i6[3] = 0xffffffff;
return (ipf_ifpfillv6addr(atype, sin6, &mask,
inp, inpmask));
}
#endif
}
return (0);
}
/*
* This function is not meant to be random, rather just produce a
* sequence of numbers that isn't linear to show "randomness".
*/
u_32_t
ipf_random()
{
static unsigned int last = 0xa5a5a5a5;
static int calls = 0;
int number;
calls++;
/*
* These are deliberately chosen to ensure that there is some
* attempt to test whether the output covers the range in test n18.
*/
switch (calls)
{
case 1 :
number = 0;
break;
case 2 :
number = 4;
break;
case 3 :
number = 3999;
break;
case 4 :
number = 4000;
break;
case 5 :
number = 48999;
break;
case 6 :
number = 49000;
break;
default :
number = last;
last *= calls;
last++;
number ^= last;
break;
}
return (number);
}
int
ipf_verifysrc(fin)
fr_info_t *fin;
{
return (1);
}
int
ipf_inject(fin, m)
fr_info_t *fin;
mb_t *m;
{
FREE_MB_T(m);
return (0);
}
u_int
ipf_pcksum(fin, hlen, sum)
fr_info_t *fin;
int hlen;
u_int sum;
{
u_short *sp;
u_int sum2;
int slen;
slen = fin->fin_plen - hlen;
sp = (u_short *)((u_char *)fin->fin_ip + hlen);
for (; slen > 1; slen -= 2)
sum += *sp++;
if (slen)
sum += ntohs(*(u_char *)sp << 8);
while (sum > 0xffff)
sum = (sum & 0xffff) + (sum >> 16);
sum2 = (u_short)(~sum & 0xffff);
return (sum2);
}
void *
ipf_pullup(m, fin, plen)
mb_t *m;
fr_info_t *fin;
int plen;
{
if (M_LEN(m) >= plen)
return (fin->fin_ip);
/*
* Fake ipf_pullup failing
*/
fin->fin_reason = FRB_PULLUP;
*fin->fin_mp = NULL;
fin->fin_m = NULL;
fin->fin_ip = NULL;
return (NULL);
}