1/*
2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include "internal/internal.h"
11#include <linux/icmp.h>
12#include <linux/icmpv6.h>
13
14static const uint8_t invmap_icmp[] = {
15	[ICMP_ECHO]		= ICMP_ECHOREPLY + 1,
16	[ICMP_ECHOREPLY]	= ICMP_ECHO + 1,
17	[ICMP_TIMESTAMP]	= ICMP_TIMESTAMPREPLY + 1,
18	[ICMP_TIMESTAMPREPLY]	= ICMP_TIMESTAMP + 1,
19	[ICMP_INFO_REQUEST]	= ICMP_INFO_REPLY + 1,
20	[ICMP_INFO_REPLY]	= ICMP_INFO_REQUEST + 1,
21	[ICMP_ADDRESS]		= ICMP_ADDRESSREPLY + 1,
22	[ICMP_ADDRESSREPLY]	= ICMP_ADDRESS + 1
23};
24
25#ifndef ICMPV6_NI_QUERY
26#define ICMPV6_NI_QUERY 139
27#endif
28
29#ifndef ICMPV6_NI_REPLY
30#define ICMPV6_NI_REPLY 140
31#endif
32
33static const uint8_t invmap_icmpv6[] = {
34	[ICMPV6_ECHO_REQUEST - 128]	= ICMPV6_ECHO_REPLY + 1,
35	[ICMPV6_ECHO_REPLY - 128]	= ICMPV6_ECHO_REQUEST + 1,
36	[ICMPV6_NI_QUERY - 128]		= ICMPV6_NI_QUERY + 1,
37	[ICMPV6_NI_REPLY - 128]		= ICMPV6_NI_REPLY + 1
38};
39
40static void set_attr_grp_orig_ipv4(struct nf_conntrack *ct, const void *value)
41{
42	const struct nfct_attr_grp_ipv4 *this = value;
43	ct->head.orig.src.v4 = this->src;
44	ct->head.orig.dst.v4 = this->dst;
45	ct->head.orig.l3protonum = AF_INET;
46}
47
48static void set_attr_grp_repl_ipv4(struct nf_conntrack *ct, const void *value)
49{
50	const struct nfct_attr_grp_ipv4 *this = value;
51	ct->repl.src.v4 = this->src;
52	ct->repl.dst.v4 = this->dst;
53	ct->repl.l3protonum = AF_INET;
54}
55
56static void set_attr_grp_orig_ipv6(struct nf_conntrack *ct, const void *value)
57{
58	const struct nfct_attr_grp_ipv6 *this = value;
59	memcpy(&ct->head.orig.src.v6, this->src, sizeof(uint32_t)*4);
60	memcpy(&ct->head.orig.dst.v6, this->dst, sizeof(uint32_t)*4);
61	ct->head.orig.l3protonum = AF_INET6;
62}
63
64static void set_attr_grp_repl_ipv6(struct nf_conntrack *ct, const void *value)
65{
66	const struct nfct_attr_grp_ipv6 *this = value;
67	memcpy(&ct->repl.src.v6, this->src, sizeof(uint32_t)*4);
68	memcpy(&ct->repl.dst.v6, this->dst, sizeof(uint32_t)*4);
69	ct->repl.l3protonum = AF_INET6;
70}
71
72static void set_attr_grp_orig_port(struct nf_conntrack *ct, const void *value)
73{
74	const struct nfct_attr_grp_port *this = value;
75	ct->head.orig.l4src.all = this->sport;
76	ct->head.orig.l4dst.all = this->dport;
77}
78
79static void set_attr_grp_repl_port(struct nf_conntrack *ct, const void *value)
80{
81	const struct nfct_attr_grp_port *this = value;
82	ct->repl.l4src.all = this->sport;
83	ct->repl.l4dst.all = this->dport;
84}
85
86static void set_attr_grp_icmp(struct nf_conntrack *ct, const void *value)
87{
88	uint8_t rtype;
89	const struct nfct_attr_grp_icmp *this = value;
90
91	ct->head.orig.l4dst.icmp.type = this->type;
92
93	switch(ct->head.orig.l3protonum) {
94		case AF_INET:
95			rtype = invmap_icmp[this->type];
96			break;
97
98		case AF_INET6:
99			rtype = invmap_icmpv6[this->type - 128];
100			break;
101
102		default:
103			rtype = 0;	/* not found */
104	}
105
106	if (rtype)
107		ct->repl.l4dst.icmp.type = rtype - 1;
108	else
109		ct->repl.l4dst.icmp.type = 255;	/* -EINVAL */
110
111	ct->head.orig.l4dst.icmp.code = this->code;
112	ct->repl.l4dst.icmp.code = this->code;
113
114	ct->head.orig.l4src.icmp.id = this->id;
115	ct->repl.l4src.icmp.id = this->id;
116}
117
118static void set_attr_grp_master_ipv4(struct nf_conntrack *ct, const void *value)
119{
120	const struct nfct_attr_grp_ipv4 *this = value;
121	ct->master.src.v4 = this->src;
122	ct->master.dst.v4 = this->dst;
123	ct->master.l3protonum = AF_INET;
124}
125
126static void set_attr_grp_master_ipv6(struct nf_conntrack *ct, const void *value)
127{
128	const struct nfct_attr_grp_ipv6 *this = value;
129	memcpy(&ct->master.src.v6, this->src, sizeof(uint32_t)*4);
130	memcpy(&ct->master.dst.v6, this->dst, sizeof(uint32_t)*4);
131	ct->master.l3protonum = AF_INET6;
132}
133
134static void set_attr_grp_master_port(struct nf_conntrack *ct, const void *value)
135{
136	const struct nfct_attr_grp_port *this = value;
137	ct->master.l4src.all = this->sport;
138	ct->master.l4dst.all = this->dport;
139}
140
141static void set_attr_grp_do_nothing(struct nf_conntrack *ct, const void *value)
142{
143}
144
145const set_attr_grp set_attr_grp_array[ATTR_GRP_MAX] = {
146	[ATTR_GRP_ORIG_IPV4]		= set_attr_grp_orig_ipv4,
147	[ATTR_GRP_REPL_IPV4]		= set_attr_grp_repl_ipv4,
148	[ATTR_GRP_ORIG_IPV6]		= set_attr_grp_orig_ipv6,
149	[ATTR_GRP_REPL_IPV6]		= set_attr_grp_repl_ipv6,
150	[ATTR_GRP_ORIG_PORT]		= set_attr_grp_orig_port,
151	[ATTR_GRP_REPL_PORT]		= set_attr_grp_repl_port,
152	[ATTR_GRP_ICMP]			= set_attr_grp_icmp,
153	[ATTR_GRP_MASTER_IPV4]		= set_attr_grp_master_ipv4,
154	[ATTR_GRP_MASTER_IPV6]		= set_attr_grp_master_ipv6,
155	[ATTR_GRP_MASTER_PORT]		= set_attr_grp_master_port,
156	[ATTR_GRP_ORIG_COUNTERS]	= set_attr_grp_do_nothing,
157	[ATTR_GRP_REPL_COUNTERS]	= set_attr_grp_do_nothing,
158	[ATTR_GRP_ORIG_ADDR_SRC]	= set_attr_grp_do_nothing,
159	[ATTR_GRP_ORIG_ADDR_DST]	= set_attr_grp_do_nothing,
160	[ATTR_GRP_REPL_ADDR_SRC]	= set_attr_grp_do_nothing,
161	[ATTR_GRP_REPL_ADDR_DST]	= set_attr_grp_do_nothing,
162};
163