blob: 5add7befa26fdd53a5c1b24ba6449e5636caa033 [file] [log] [blame]
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation (or any later at your option).
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
#include "helper.h"
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
int
cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master,
uint32_t class,
union nfct_attr_grp_addr *saddr,
union nfct_attr_grp_addr *daddr,
uint8_t l4proto, uint16_t *sport, uint16_t *dport,
uint32_t flags)
{
struct nf_conntrack *expected, *mask;
expected = nfct_new();
if (!expected)
return -1;
mask = nfct_new();
if (!mask)
return -1;
if (saddr) {
switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) {
uint32_t addr[4];
case AF_INET:
nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET);
nfct_set_attr_u32(expected, ATTR_IPV4_SRC, saddr->ip);
nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET);
nfct_set_attr_u32(mask, ATTR_IPV4_SRC, 0xffffffff);
break;
case AF_INET6:
nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6);
nfct_set_attr(expected, ATTR_IPV6_SRC, saddr->ip6);
memset(addr, 0xff, sizeof(addr));
nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET6);
nfct_set_attr(mask, ATTR_IPV6_SRC, addr);
break;
default:
break;
}
} else {
switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) {
uint32_t addr[4];
case AF_INET:
nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET);
nfct_set_attr_u32(expected, ATTR_IPV4_SRC, 0x00000000);
nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET);
nfct_set_attr_u32(mask, ATTR_IPV4_SRC, 0x00000000);
break;
case AF_INET6:
memset(addr, 0x00, sizeof(addr));
nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6);
nfct_set_attr(expected, ATTR_IPV6_SRC, addr);
nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET6);
nfct_set_attr(mask, ATTR_IPV6_SRC, addr);
break;
default:
break;
}
}
if (sport) {
switch(l4proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
nfct_set_attr_u8(expected, ATTR_L4PROTO, l4proto);
nfct_set_attr_u16(expected, ATTR_PORT_SRC, *sport);
nfct_set_attr_u8(mask, ATTR_L4PROTO, l4proto);
nfct_set_attr_u16(mask, ATTR_PORT_SRC, 0xffff);
break;
default:
break;
}
} else {
switch(l4proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
nfct_set_attr_u8(expected, ATTR_L4PROTO, l4proto);
nfct_set_attr_u16(expected, ATTR_PORT_SRC, 0x0000);
nfct_set_attr_u8(mask, ATTR_L4PROTO, l4proto);
nfct_set_attr_u16(mask, ATTR_PORT_SRC, 0x0000);
break;
default:
break;
}
}
switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) {
uint32_t addr[4];
case AF_INET:
nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET);
nfct_set_attr_u32(expected, ATTR_IPV4_DST, daddr->ip);
nfct_set_attr_u32(mask, ATTR_IPV4_DST, 0xffffffff);
break;
case AF_INET6:
nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6);
nfct_set_attr(expected, ATTR_IPV6_DST, daddr->ip6);
memset(addr, 0xff, sizeof(addr));
nfct_set_attr(mask, ATTR_IPV6_DST, addr);
break;
default:
break;
}
switch(l4proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
nfct_set_attr_u8(expected, ATTR_L4PROTO, l4proto);
nfct_set_attr_u16(expected, ATTR_PORT_DST, *dport);
nfct_set_attr_u8(mask, ATTR_L4PROTO, l4proto);
nfct_set_attr_u16(mask, ATTR_PORT_DST, 0xffff);
break;
default:
break;
}
nfexp_set_attr(exp, ATTR_EXP_MASTER, master);
nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected);
nfexp_set_attr(exp, ATTR_EXP_MASK, mask);
nfexp_set_attr_u32(exp, ATTR_EXP_FLAGS, flags);
nfct_destroy(expected);
nfct_destroy(mask);
return 0;
}
static int cthelper_expect_cmd(struct nf_expect *exp, int cmd)
{
int ret;
struct nfct_handle *h;
h = nfct_open(EXPECT, 0);
if (!h)
return -1;
ret = nfexp_query(h, cmd, exp);
nfct_close(h);
return ret;
}
int cthelper_add_expect(struct nf_expect *exp)
{
return cthelper_expect_cmd(exp, NFCT_Q_CREATE_UPDATE);
}
int cthelper_del_expect(struct nf_expect *exp)
{
return cthelper_expect_cmd(exp, NFCT_Q_DESTROY);
}
void
cthelper_get_addr_src(struct nf_conntrack *ct, int dir,
union nfct_attr_grp_addr *addr)
{
switch (dir) {
case MYCT_DIR_ORIG:
nfct_get_attr_grp(ct, ATTR_GRP_ORIG_ADDR_SRC, addr);
break;
case MYCT_DIR_REPL:
nfct_get_attr_grp(ct, ATTR_GRP_REPL_ADDR_SRC, addr);
break;
}
}
void
cthelper_get_addr_dst(struct nf_conntrack *ct, int dir,
union nfct_attr_grp_addr *addr)
{
switch (dir) {
case MYCT_DIR_ORIG:
nfct_get_attr_grp(ct, ATTR_GRP_ORIG_ADDR_DST, addr);
break;
case MYCT_DIR_REPL:
nfct_get_attr_grp(ct, ATTR_GRP_REPL_ADDR_DST, addr);
break;
}
}
void cthelper_get_port_src(struct nf_conntrack *ct, int dir, uint16_t *port)
{
switch (dir) {
case MYCT_DIR_ORIG:
*port = nfct_get_attr_u16(ct, ATTR_PORT_SRC);
break;
case MYCT_DIR_REPL:
*port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
break;
}
}
void cthelper_get_port_dst(struct nf_conntrack *ct, int dir, uint16_t *port)
{
switch (dir) {
case MYCT_DIR_ORIG:
*port = nfct_get_attr_u16(ct, ATTR_PORT_DST);
break;
case MYCT_DIR_REPL:
*port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST);
break;
}
}