1/*
2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation (or any later at your option).
7 *
8 * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
9 */
10
11#include "helper.h"
12
13#include <stdio.h>
14#include <string.h>
15#include <limits.h>
16#include <errno.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <unistd.h>
20#include <dlfcn.h>
21
22int
23cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master,
24		  uint32_t class,
25		  union nfct_attr_grp_addr *saddr,
26		  union nfct_attr_grp_addr *daddr,
27		  uint8_t l4proto, uint16_t *sport, uint16_t *dport,
28		  uint32_t flags)
29{
30	struct nf_conntrack *expected, *mask;
31
32	expected = nfct_new();
33	if (!expected)
34		return -1;
35
36	mask = nfct_new();
37	if (!mask)
38		return -1;
39
40	if (saddr) {
41		switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) {
42		int i;
43		uint32_t addr[4] = {};
44
45		case AF_INET:
46			nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET);
47			nfct_set_attr_u32(expected, ATTR_IPV4_SRC, saddr->ip);
48
49			nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET);
50			nfct_set_attr_u32(mask, ATTR_IPV4_SRC, 0xffffffff);
51			break;
52		case AF_INET6:
53			nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6);
54			nfct_set_attr(expected, ATTR_IPV6_SRC, saddr->ip6);
55
56			for (i=0; i<4; i++)
57				memset(addr, 0xffffffff, sizeof(uint32_t));
58
59			nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET6);
60			nfct_set_attr(mask, ATTR_IPV6_SRC, addr);
61			break;
62		default:
63			break;
64		}
65	} else {
66		switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) {
67		int i;
68		uint32_t addr[4] = {};
69
70		case AF_INET:
71			nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET);
72			nfct_set_attr_u32(expected, ATTR_IPV4_SRC, 0x00000000);
73
74			nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET);
75			nfct_set_attr_u32(mask, ATTR_IPV4_SRC, 0x00000000);
76			break;
77		case AF_INET6:
78			for (i=0; i<4; i++)
79				memset(addr, 0x00000000, sizeof(uint32_t));
80
81			nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6);
82			nfct_set_attr(expected, ATTR_IPV6_SRC, addr);
83
84			nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET6);
85			nfct_set_attr(mask, ATTR_IPV6_SRC, addr);
86			break;
87		default:
88			break;
89		}
90	}
91
92	if (sport) {
93		switch(l4proto) {
94		case IPPROTO_TCP:
95		case IPPROTO_UDP:
96			nfct_set_attr_u8(expected, ATTR_L4PROTO, l4proto);
97			nfct_set_attr_u16(expected, ATTR_PORT_SRC, *sport);
98			nfct_set_attr_u8(mask, ATTR_L4PROTO, l4proto);
99			nfct_set_attr_u16(mask, ATTR_PORT_SRC, 0xffff);
100			break;
101		default:
102			break;
103		}
104	} else {
105		switch(l4proto) {
106		case IPPROTO_TCP:
107		case IPPROTO_UDP:
108			nfct_set_attr_u8(expected, ATTR_L4PROTO, l4proto);
109			nfct_set_attr_u16(expected, ATTR_PORT_SRC, 0x0000);
110			nfct_set_attr_u8(mask, ATTR_L4PROTO, l4proto);
111			nfct_set_attr_u16(mask, ATTR_PORT_SRC, 0x0000);
112			break;
113		default:
114			break;
115		}
116	}
117
118	switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) {
119	uint32_t addr[4] = {};
120	int i;
121
122	case AF_INET:
123		nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET);
124		nfct_set_attr_u32(expected, ATTR_IPV4_DST, daddr->ip);
125		nfct_set_attr_u32(mask, ATTR_IPV4_DST, 0xffffffff);
126		break;
127	case AF_INET6:
128		nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6);
129		nfct_set_attr(expected, ATTR_IPV6_DST, daddr->ip6);
130
131		for (i=0; i<4; i++)
132			memset(addr, 0xffffffff, sizeof(uint32_t));
133
134		nfct_set_attr(mask, ATTR_IPV6_DST, addr);
135		break;
136	default:
137		break;
138	}
139
140	switch(l4proto) {
141	case IPPROTO_TCP:
142	case IPPROTO_UDP:
143		nfct_set_attr_u8(expected, ATTR_L4PROTO, l4proto);
144		nfct_set_attr_u16(expected, ATTR_PORT_DST, *dport);
145		nfct_set_attr_u8(mask, ATTR_L4PROTO, l4proto);
146		nfct_set_attr_u16(mask, ATTR_PORT_DST, 0xffff);
147		break;
148	default:
149		break;
150	}
151
152	nfexp_set_attr(exp, ATTR_EXP_MASTER, master);
153	nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected);
154	nfexp_set_attr(exp, ATTR_EXP_MASK, mask);
155	nfexp_set_attr_u32(exp, ATTR_EXP_FLAGS, flags);
156
157	nfct_destroy(expected);
158	nfct_destroy(mask);
159
160	return 0;
161}
162
163static int cthelper_expect_cmd(struct nf_expect *exp, int cmd)
164{
165	int ret;
166	struct nfct_handle *h;
167
168	h = nfct_open(EXPECT, 0);
169	if (!h)
170		return -1;
171
172	ret = nfexp_query(h, cmd, exp);
173
174	nfct_close(h);
175	return ret;
176}
177
178int cthelper_add_expect(struct nf_expect *exp)
179{
180	return cthelper_expect_cmd(exp, NFCT_Q_CREATE_UPDATE);
181}
182
183int cthelper_del_expect(struct nf_expect *exp)
184{
185	return cthelper_expect_cmd(exp, NFCT_Q_DESTROY);
186}
187
188void
189cthelper_get_addr_src(struct nf_conntrack *ct, int dir,
190		      union nfct_attr_grp_addr *addr)
191{
192	switch (dir) {
193	case MYCT_DIR_ORIG:
194		nfct_get_attr_grp(ct, ATTR_GRP_ORIG_ADDR_SRC, addr);
195		break;
196	case MYCT_DIR_REPL:
197		nfct_get_attr_grp(ct, ATTR_GRP_REPL_ADDR_SRC, addr);
198		break;
199	}
200}
201
202void
203cthelper_get_addr_dst(struct nf_conntrack *ct, int dir,
204		      union nfct_attr_grp_addr *addr)
205{
206	switch (dir) {
207	case MYCT_DIR_ORIG:
208		nfct_get_attr_grp(ct, ATTR_GRP_ORIG_ADDR_DST, addr);
209		break;
210	case MYCT_DIR_REPL:
211		nfct_get_attr_grp(ct, ATTR_GRP_REPL_ADDR_DST, addr);
212		break;
213	}
214}
215