1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/in.h>
4 #include <sys/socket.h>
5 #include <linux/if.h>
6 #include <linux/netfilter/nf_tables.h>
7 #include <linux/netfilter/nfnetlink.h>
8
9 #include "netlink-types-internal.h"
10 #include "string-table.h"
11
12 static const NLType nfnl_nft_table_types[] = {
13 [NFTA_TABLE_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
14 [NFTA_TABLE_FLAGS] = { .type = NETLINK_TYPE_U32 },
15 };
16
17 DEFINE_TYPE_SYSTEM(nfnl_nft_table);
18
19 static const NLType nfnl_nft_chain_hook_types[] = {
20 [NFTA_HOOK_HOOKNUM] = { .type = NETLINK_TYPE_U32 },
21 [NFTA_HOOK_PRIORITY] = { .type = NETLINK_TYPE_U32 },
22 [NFTA_HOOK_DEV] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
23 };
24
25 DEFINE_TYPE_SYSTEM(nfnl_nft_chain_hook);
26
27 static const NLType nfnl_nft_chain_types[] = {
28 [NFTA_CHAIN_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
29 [NFTA_CHAIN_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
30 [NFTA_CHAIN_HOOK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_hook_type_system },
31 [NFTA_CHAIN_TYPE] = { .type = NETLINK_TYPE_STRING, .size = 16 },
32 [NFTA_CHAIN_FLAGS] = { .type = NETLINK_TYPE_U32 },
33 };
34
35 DEFINE_TYPE_SYSTEM(nfnl_nft_chain);
36
37 static const NLType nfnl_nft_expr_meta_types[] = {
38 [NFTA_META_DREG] = { .type = NETLINK_TYPE_U32 },
39 [NFTA_META_KEY] = { .type = NETLINK_TYPE_U32 },
40 [NFTA_META_SREG] = { .type = NETLINK_TYPE_U32 },
41 };
42
43 static const NLType nfnl_nft_expr_payload_types[] = {
44 [NFTA_PAYLOAD_DREG] = { .type = NETLINK_TYPE_U32 },
45 [NFTA_PAYLOAD_BASE] = { .type = NETLINK_TYPE_U32 },
46 [NFTA_PAYLOAD_OFFSET] = { .type = NETLINK_TYPE_U32 },
47 [NFTA_PAYLOAD_LEN] = { .type = NETLINK_TYPE_U32 },
48 };
49
50 static const NLType nfnl_nft_expr_nat_types[] = {
51 [NFTA_NAT_TYPE] = { .type = NETLINK_TYPE_U32 },
52 [NFTA_NAT_FAMILY] = { .type = NETLINK_TYPE_U32 },
53 [NFTA_NAT_REG_ADDR_MIN] = { .type = NETLINK_TYPE_U32 },
54 [NFTA_NAT_REG_ADDR_MAX] = { .type = NETLINK_TYPE_U32 },
55 [NFTA_NAT_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
56 [NFTA_NAT_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
57 [NFTA_NAT_FLAGS] = { .type = NETLINK_TYPE_U32 },
58 };
59
60 static const NLType nfnl_nft_data_types[] = {
61 [NFTA_DATA_VALUE] = { .type = NETLINK_TYPE_BINARY },
62 };
63
64 DEFINE_TYPE_SYSTEM(nfnl_nft_data);
65
66 static const NLType nfnl_nft_expr_bitwise_types[] = {
67 [NFTA_BITWISE_SREG] = { .type = NETLINK_TYPE_U32 },
68 [NFTA_BITWISE_DREG] = { .type = NETLINK_TYPE_U32 },
69 [NFTA_BITWISE_LEN] = { .type = NETLINK_TYPE_U32 },
70 [NFTA_BITWISE_MASK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
71 [NFTA_BITWISE_XOR] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
72 };
73
74 static const NLType nfnl_nft_expr_cmp_types[] = {
75 [NFTA_CMP_SREG] = { .type = NETLINK_TYPE_U32 },
76 [NFTA_CMP_OP] = { .type = NETLINK_TYPE_U32 },
77 [NFTA_CMP_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
78 };
79
80 static const NLType nfnl_nft_expr_fib_types[] = {
81 [NFTA_FIB_DREG] = { .type = NETLINK_TYPE_U32 },
82 [NFTA_FIB_RESULT] = { .type = NETLINK_TYPE_U32 },
83 [NFTA_FIB_FLAGS] = { .type = NETLINK_TYPE_U32 },
84 };
85
86 static const NLType nfnl_nft_expr_lookup_types[] = {
87 [NFTA_LOOKUP_SET] = { .type = NETLINK_TYPE_STRING },
88 [NFTA_LOOKUP_SREG] = { .type = NETLINK_TYPE_U32 },
89 [NFTA_LOOKUP_DREG] = { .type = NETLINK_TYPE_U32 },
90 [NFTA_LOOKUP_FLAGS] = { .type = NETLINK_TYPE_U32 },
91 };
92
93 static const NLType nfnl_nft_expr_masq_types[] = {
94 [NFTA_MASQ_FLAGS] = { .type = NETLINK_TYPE_U32 },
95 [NFTA_MASQ_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
96 [NFTA_MASQ_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
97 };
98
99 static const NLTypeSystemUnionElement nfnl_expr_data_type_systems[] = {
100 { .name = "bitwise", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_bitwise), },
101 { .name = "cmp", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_cmp), },
102 { .name = "fib", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_fib), },
103 { .name = "lookup", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_lookup), },
104 { .name = "masq", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_masq), },
105 { .name = "meta", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_meta), },
106 { .name = "nat", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_nat), },
107 { .name = "payload", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_payload), },
108 };
109
110 DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(nfnl_expr_data, NFTA_EXPR_NAME);
111
112 static const NLType nfnl_nft_rule_expr_types[] = {
113 [NFTA_EXPR_NAME] = { .type = NETLINK_TYPE_STRING, .size = 16 },
114 [NFTA_EXPR_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &nfnl_expr_data_type_system_union },
115 };
116
117 DEFINE_TYPE_SYSTEM(nfnl_nft_rule_expr);
118
119 static const NLType nfnl_nft_rule_types[] = {
120 [NFTA_RULE_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
121 [NFTA_RULE_CHAIN] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
122 [NFTA_RULE_EXPRESSIONS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_expr_type_system }
123 };
124
125 DEFINE_TYPE_SYSTEM(nfnl_nft_rule);
126
127 static const NLType nfnl_nft_set_types[] = {
128 [NFTA_SET_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
129 [NFTA_SET_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
130 [NFTA_SET_FLAGS] = { .type = NETLINK_TYPE_U32 },
131 [NFTA_SET_KEY_TYPE] = { .type = NETLINK_TYPE_U32 },
132 [NFTA_SET_KEY_LEN] = { .type = NETLINK_TYPE_U32 },
133 [NFTA_SET_DATA_TYPE] = { .type = NETLINK_TYPE_U32 },
134 [NFTA_SET_DATA_LEN] = { .type = NETLINK_TYPE_U32 },
135 [NFTA_SET_POLICY] = { .type = NETLINK_TYPE_U32 },
136 [NFTA_SET_ID] = { .type = NETLINK_TYPE_U32 },
137 };
138
139 DEFINE_TYPE_SYSTEM(nfnl_nft_set);
140
141 static const NLType nfnl_nft_setelem_types[] = {
142 [NFTA_SET_ELEM_KEY] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
143 [NFTA_SET_ELEM_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
144 [NFTA_SET_ELEM_FLAGS] = { .type = NETLINK_TYPE_U32 },
145 };
146
147 DEFINE_TYPE_SYSTEM(nfnl_nft_setelem);
148
149 static const NLType nfnl_nft_setelem_list_types[] = {
150 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
151 [NFTA_SET_ELEM_LIST_SET] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
152 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_type_system },
153 };
154
155 DEFINE_TYPE_SYSTEM(nfnl_nft_setelem_list);
156
157 static const NLType nfnl_subsys_nft_types [] = {
158 [NFT_MSG_DELTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
159 [NFT_MSG_NEWTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
160 [NFT_MSG_NEWCHAIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_type_system, .size = sizeof(struct nfgenmsg) },
161 [NFT_MSG_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_type_system, .size = sizeof(struct nfgenmsg) },
162 [NFT_MSG_NEWSET] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_set_type_system, .size = sizeof(struct nfgenmsg) },
163 [NFT_MSG_NEWSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
164 [NFT_MSG_DELSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
165 };
166
167 DEFINE_TYPE_SYSTEM(nfnl_subsys_nft);
168
169 static const NLType nfnl_msg_batch_types [] = {
170 [NFNL_BATCH_GENID] = { .type = NETLINK_TYPE_U32 }
171 };
172
173 DEFINE_TYPE_SYSTEM(nfnl_msg_batch);
174
175 static const NLType nfnl_subsys_none_types[] = {
176 [NFNL_MSG_BATCH_BEGIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
177 [NFNL_MSG_BATCH_END] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
178 };
179
180 DEFINE_TYPE_SYSTEM(nfnl_subsys_none);
181
182 static const NLType nfnl_types[] = {
183 [NFNL_SUBSYS_NONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_subsys_none_type_system },
184 [NFNL_SUBSYS_NFTABLES] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_subsys_nft_type_system },
185 };
186
187 DEFINE_TYPE_SYSTEM(nfnl);
188
nfnl_get_type(uint16_t nlmsg_type)189 const NLType *nfnl_get_type(uint16_t nlmsg_type) {
190 const NLTypeSystem *subsys;
191
192 subsys = type_system_get_type_system(&nfnl_type_system, nlmsg_type >> 8);
193 if (!subsys)
194 return NULL;
195
196 return type_system_get_type(subsys, nlmsg_type & ((1U << 8) - 1));
197 }
198