nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * lib/netfilter/ct_obj.c Conntrack Object |
||
3 | * |
||
4 | * This library is free software; you can redistribute it and/or |
||
5 | * modify it under the terms of the GNU Lesser General Public |
||
6 | * License as published by the Free Software Foundation version 2.1 |
||
7 | * of the License. |
||
8 | * |
||
9 | * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> |
||
10 | * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> |
||
11 | * Copyright (c) 2007 Secure Computing Corporation |
||
12 | */ |
||
13 | |||
14 | #include <sys/types.h> |
||
15 | #include <linux/netfilter/nfnetlink_conntrack.h> |
||
16 | #include <linux/netfilter/nf_conntrack_common.h> |
||
17 | #include <linux/netfilter/nf_conntrack_tcp.h> |
||
18 | |||
19 | #include <netlink-local.h> |
||
20 | #include <netlink/netfilter/nfnl.h> |
||
21 | #include <netlink/netfilter/ct.h> |
||
22 | |||
23 | /** @cond SKIP */ |
||
24 | #define CT_ATTR_FAMILY (1UL << 0) |
||
25 | #define CT_ATTR_PROTO (1UL << 1) |
||
26 | |||
27 | #define CT_ATTR_TCP_STATE (1UL << 2) |
||
28 | |||
29 | #define CT_ATTR_STATUS (1UL << 3) |
||
30 | #define CT_ATTR_TIMEOUT (1UL << 4) |
||
31 | #define CT_ATTR_MARK (1UL << 5) |
||
32 | #define CT_ATTR_USE (1UL << 6) |
||
33 | #define CT_ATTR_ID (1UL << 7) |
||
34 | |||
35 | #define CT_ATTR_ORIG_SRC (1UL << 8) |
||
36 | #define CT_ATTR_ORIG_DST (1UL << 9) |
||
37 | #define CT_ATTR_ORIG_SRC_PORT (1UL << 10) |
||
38 | #define CT_ATTR_ORIG_DST_PORT (1UL << 11) |
||
39 | #define CT_ATTR_ORIG_ICMP_ID (1UL << 12) |
||
40 | #define CT_ATTR_ORIG_ICMP_TYPE (1UL << 13) |
||
41 | #define CT_ATTR_ORIG_ICMP_CODE (1UL << 14) |
||
42 | #define CT_ATTR_ORIG_PACKETS (1UL << 15) |
||
43 | #define CT_ATTR_ORIG_BYTES (1UL << 16) |
||
44 | |||
45 | #define CT_ATTR_REPL_SRC (1UL << 17) |
||
46 | #define CT_ATTR_REPL_DST (1UL << 18) |
||
47 | #define CT_ATTR_REPL_SRC_PORT (1UL << 19) |
||
48 | #define CT_ATTR_REPL_DST_PORT (1UL << 20) |
||
49 | #define CT_ATTR_REPL_ICMP_ID (1UL << 21) |
||
50 | #define CT_ATTR_REPL_ICMP_TYPE (1UL << 22) |
||
51 | #define CT_ATTR_REPL_ICMP_CODE (1UL << 23) |
||
52 | #define CT_ATTR_REPL_PACKETS (1UL << 24) |
||
53 | #define CT_ATTR_REPL_BYTES (1UL << 25) |
||
54 | /** @endcond */ |
||
55 | |||
56 | static void ct_free_data(struct nl_object *c) |
||
57 | { |
||
58 | struct nfnl_ct *ct = (struct nfnl_ct *) c; |
||
59 | |||
60 | if (ct == NULL) |
||
61 | return; |
||
62 | |||
63 | nl_addr_put(ct->ct_orig.src); |
||
64 | nl_addr_put(ct->ct_orig.dst); |
||
65 | nl_addr_put(ct->ct_repl.src); |
||
66 | nl_addr_put(ct->ct_repl.dst); |
||
67 | } |
||
68 | |||
69 | static int ct_clone(struct nl_object *_dst, struct nl_object *_src) |
||
70 | { |
||
71 | struct nfnl_ct *dst = (struct nfnl_ct *) _dst; |
||
72 | struct nfnl_ct *src = (struct nfnl_ct *) _src; |
||
73 | struct nl_addr *addr; |
||
74 | |||
75 | if (src->ct_orig.src) { |
||
76 | addr = nl_addr_clone(src->ct_orig.src); |
||
77 | if (!addr) |
||
78 | return -NLE_NOMEM; |
||
79 | dst->ct_orig.src = addr; |
||
80 | } |
||
81 | |||
82 | if (src->ct_orig.dst) { |
||
83 | addr = nl_addr_clone(src->ct_orig.dst); |
||
84 | if (!addr) |
||
85 | return -NLE_NOMEM; |
||
86 | dst->ct_orig.dst = addr; |
||
87 | } |
||
88 | |||
89 | if (src->ct_repl.src) { |
||
90 | addr = nl_addr_clone(src->ct_repl.src); |
||
91 | if (!addr) |
||
92 | return -NLE_NOMEM; |
||
93 | dst->ct_repl.src = addr; |
||
94 | } |
||
95 | |||
96 | if (src->ct_repl.dst) { |
||
97 | addr = nl_addr_clone(src->ct_repl.dst); |
||
98 | if (!addr) |
||
99 | return -NLE_NOMEM; |
||
100 | dst->ct_repl.dst = addr; |
||
101 | } |
||
102 | |||
103 | return 0; |
||
104 | } |
||
105 | |||
106 | static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port) |
||
107 | { |
||
108 | char buf[64]; |
||
109 | |||
110 | if (addr) |
||
111 | nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf))); |
||
112 | |||
113 | if (port) |
||
114 | nl_dump(p, ":%u ", port); |
||
115 | else if (addr) |
||
116 | nl_dump(p, " "); |
||
117 | } |
||
118 | |||
119 | static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int reply) |
||
120 | { |
||
121 | if (nfnl_ct_test_icmp_type(ct, reply)) |
||
122 | nl_dump(p, "icmp type %d ", nfnl_ct_get_icmp_type(ct, reply)); |
||
123 | |||
124 | if (nfnl_ct_test_icmp_type(ct, reply)) |
||
125 | nl_dump(p, "code %d ", nfnl_ct_get_icmp_code(ct, reply)); |
||
126 | |||
127 | if (nfnl_ct_test_icmp_type(ct, reply)) |
||
128 | nl_dump(p, "id %d ", nfnl_ct_get_icmp_id(ct, reply)); |
||
129 | } |
||
130 | |||
131 | static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p) |
||
132 | { |
||
133 | struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst; |
||
134 | int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0; |
||
135 | int sync = 0; |
||
136 | |||
137 | orig_src = nfnl_ct_get_src(ct, 0); |
||
138 | orig_dst = nfnl_ct_get_dst(ct, 0); |
||
139 | reply_src = nfnl_ct_get_src(ct, 1); |
||
140 | reply_dst = nfnl_ct_get_dst(ct, 1); |
||
141 | |||
142 | if (nfnl_ct_test_src_port(ct, 0)) |
||
143 | orig_sport = nfnl_ct_get_src_port(ct, 0); |
||
144 | |||
145 | if (nfnl_ct_test_dst_port(ct, 0)) |
||
146 | orig_dport = nfnl_ct_get_dst_port(ct, 0); |
||
147 | |||
148 | if (nfnl_ct_test_src_port(ct, 1)) |
||
149 | reply_sport = nfnl_ct_get_src_port(ct, 1); |
||
150 | |||
151 | if (nfnl_ct_test_dst_port(ct, 1)) |
||
152 | reply_dport = nfnl_ct_get_dst_port(ct, 1); |
||
153 | |||
154 | if (orig_src && orig_dst && reply_src && reply_dst && |
||
155 | orig_sport == reply_dport && orig_dport == reply_sport && |
||
156 | !nl_addr_cmp(orig_src, reply_dst) && |
||
157 | !nl_addr_cmp(orig_dst, reply_src)) |
||
158 | sync = 1; |
||
159 | |||
160 | dump_addr(p, orig_src, orig_sport); |
||
161 | nl_dump(p, sync ? "<-> " : "-> "); |
||
162 | dump_addr(p, orig_dst, orig_dport); |
||
163 | dump_icmp(p, ct, 0); |
||
164 | |||
165 | if (!sync) { |
||
166 | dump_addr(p, reply_src, reply_sport); |
||
167 | nl_dump(p, "<- "); |
||
168 | dump_addr(p, reply_dst, reply_dport); |
||
169 | dump_icmp(p, ct, 1); |
||
170 | } |
||
171 | } |
||
172 | |||
173 | /* Compatible with /proc/net/nf_conntrack */ |
||
174 | static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p) |
||
175 | { |
||
176 | struct nfnl_ct *ct = (struct nfnl_ct *) a; |
||
177 | char buf[64]; |
||
178 | |||
179 | nl_new_line(p); |
||
180 | |||
181 | if (nfnl_ct_test_proto(ct)) |
||
182 | nl_dump(p, "%s ", |
||
183 | nl_ip_proto2str(nfnl_ct_get_proto(ct), buf, sizeof(buf))); |
||
184 | |||
185 | if (nfnl_ct_test_tcp_state(ct)) |
||
186 | nl_dump(p, "%s ", |
||
187 | nfnl_ct_tcp_state2str(nfnl_ct_get_tcp_state(ct), |
||
188 | buf, sizeof(buf))); |
||
189 | |||
190 | ct_dump_tuples(ct, p); |
||
191 | |||
192 | if (nfnl_ct_test_mark(ct) && nfnl_ct_get_mark(ct)) |
||
193 | nl_dump(p, "mark %u ", nfnl_ct_get_mark(ct)); |
||
194 | |||
195 | nl_dump(p, "\n"); |
||
196 | } |
||
197 | |||
198 | static void ct_dump_details(struct nl_object *a, struct nl_dump_params *p) |
||
199 | { |
||
200 | struct nfnl_ct *ct = (struct nfnl_ct *) a; |
||
201 | char buf[64]; |
||
202 | int fp = 0; |
||
203 | |||
204 | ct_dump_line(a, p); |
||
205 | |||
206 | nl_dump(p, " id 0x%x ", ct->ct_id); |
||
207 | nl_dump_line(p, "family %s ", |
||
208 | nl_af2str(ct->ct_family, buf, sizeof(buf))); |
||
209 | |||
210 | if (nfnl_ct_test_use(ct)) |
||
211 | nl_dump(p, "refcnt %u ", nfnl_ct_get_use(ct)); |
||
212 | |||
213 | if (nfnl_ct_test_timeout(ct)) { |
||
214 | uint64_t timeout_ms = nfnl_ct_get_timeout(ct) * 1000UL; |
||
215 | nl_dump(p, "timeout %s ", |
||
216 | nl_msec2str(timeout_ms, buf, sizeof(buf))); |
||
217 | } |
||
218 | |||
219 | if (ct->ct_status) |
||
220 | nl_dump(p, "<"); |
||
221 | |||
222 | #define PRINT_FLAG(str) \ |
||
223 | { nl_dump(p, "%s%s", fp++ ? "," : "", (str)); } |
||
224 | |||
225 | if (ct->ct_status & IPS_EXPECTED) |
||
226 | PRINT_FLAG("EXPECTED"); |
||
227 | if (!(ct->ct_status & IPS_SEEN_REPLY)) |
||
228 | PRINT_FLAG("NOREPLY"); |
||
229 | if (ct->ct_status & IPS_ASSURED) |
||
230 | PRINT_FLAG("ASSURED"); |
||
231 | if (!(ct->ct_status & IPS_CONFIRMED)) |
||
232 | PRINT_FLAG("NOTSENT"); |
||
233 | if (ct->ct_status & IPS_SRC_NAT) |
||
234 | PRINT_FLAG("SNAT"); |
||
235 | if (ct->ct_status & IPS_DST_NAT) |
||
236 | PRINT_FLAG("DNAT"); |
||
237 | if (ct->ct_status & IPS_SEQ_ADJUST) |
||
238 | PRINT_FLAG("SEQADJUST"); |
||
239 | if (!(ct->ct_status & IPS_SRC_NAT_DONE)) |
||
240 | PRINT_FLAG("SNAT_INIT"); |
||
241 | if (!(ct->ct_status & IPS_DST_NAT_DONE)) |
||
242 | PRINT_FLAG("DNAT_INIT"); |
||
243 | if (ct->ct_status & IPS_DYING) |
||
244 | PRINT_FLAG("DYING"); |
||
245 | if (ct->ct_status & IPS_FIXED_TIMEOUT) |
||
246 | PRINT_FLAG("FIXED_TIMEOUT"); |
||
247 | #undef PRINT_FLAG |
||
248 | |||
249 | if (ct->ct_status) |
||
250 | nl_dump(p, ">"); |
||
251 | nl_dump(p, "\n"); |
||
252 | } |
||
253 | |||
254 | static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p) |
||
255 | { |
||
256 | struct nfnl_ct *ct = (struct nfnl_ct *) a; |
||
257 | double res; |
||
258 | char *unit; |
||
259 | |||
260 | ct_dump_details(a, p); |
||
261 | |||
262 | nl_dump_line(p, " # packets volume\n"); |
||
263 | |||
264 | res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 1), &unit); |
||
265 | nl_dump_line(p, " rx %10llu %7.2f %s\n", |
||
266 | nfnl_ct_get_packets(ct, 1), res, unit); |
||
267 | |||
268 | res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 0), &unit); |
||
269 | nl_dump_line(p, " tx %10llu %7.2f %s\n", |
||
270 | nfnl_ct_get_packets(ct, 0), res, unit); |
||
271 | } |
||
272 | |||
273 | static int ct_compare(struct nl_object *_a, struct nl_object *_b, |
||
274 | uint32_t attrs, int flags) |
||
275 | { |
||
276 | struct nfnl_ct *a = (struct nfnl_ct *) _a; |
||
277 | struct nfnl_ct *b = (struct nfnl_ct *) _b; |
||
278 | int diff = 0; |
||
279 | |||
280 | #define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR) |
||
281 | #define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD) |
||
282 | #define CT_DIFF_ADDR(ATTR, FIELD) \ |
||
283 | ((flags & LOOSE_COMPARISON) \ |
||
284 | ? CT_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \ |
||
285 | : CT_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD))) |
||
286 | |||
287 | diff |= CT_DIFF_VAL(FAMILY, ct_family); |
||
288 | diff |= CT_DIFF_VAL(PROTO, ct_proto); |
||
289 | diff |= CT_DIFF_VAL(TCP_STATE, ct_protoinfo.tcp.state); |
||
290 | diff |= CT_DIFF_VAL(TIMEOUT, ct_timeout); |
||
291 | diff |= CT_DIFF_VAL(MARK, ct_mark); |
||
292 | diff |= CT_DIFF_VAL(USE, ct_use); |
||
293 | diff |= CT_DIFF_VAL(ID, ct_id); |
||
294 | diff |= CT_DIFF_ADDR(ORIG_SRC, ct_orig.src); |
||
295 | diff |= CT_DIFF_ADDR(ORIG_DST, ct_orig.dst); |
||
296 | diff |= CT_DIFF_VAL(ORIG_SRC_PORT, ct_orig.proto.port.src); |
||
297 | diff |= CT_DIFF_VAL(ORIG_DST_PORT, ct_orig.proto.port.dst); |
||
298 | diff |= CT_DIFF_VAL(ORIG_ICMP_ID, ct_orig.proto.icmp.id); |
||
299 | diff |= CT_DIFF_VAL(ORIG_ICMP_TYPE, ct_orig.proto.icmp.type); |
||
300 | diff |= CT_DIFF_VAL(ORIG_ICMP_CODE, ct_orig.proto.icmp.code); |
||
301 | diff |= CT_DIFF_VAL(ORIG_PACKETS, ct_orig.packets); |
||
302 | diff |= CT_DIFF_VAL(ORIG_BYTES, ct_orig.bytes); |
||
303 | diff |= CT_DIFF_ADDR(REPL_SRC, ct_repl.src); |
||
304 | diff |= CT_DIFF_ADDR(REPL_DST, ct_repl.dst); |
||
305 | diff |= CT_DIFF_VAL(REPL_SRC_PORT, ct_repl.proto.port.src); |
||
306 | diff |= CT_DIFF_VAL(REPL_DST_PORT, ct_repl.proto.port.dst); |
||
307 | diff |= CT_DIFF_VAL(REPL_ICMP_ID, ct_repl.proto.icmp.id); |
||
308 | diff |= CT_DIFF_VAL(REPL_ICMP_TYPE, ct_repl.proto.icmp.type); |
||
309 | diff |= CT_DIFF_VAL(REPL_ICMP_CODE, ct_repl.proto.icmp.code); |
||
310 | diff |= CT_DIFF_VAL(REPL_PACKETS, ct_repl.packets); |
||
311 | diff |= CT_DIFF_VAL(REPL_BYTES, ct_repl.bytes); |
||
312 | |||
313 | if (flags & LOOSE_COMPARISON) |
||
314 | diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) & |
||
315 | b->ct_status_mask); |
||
316 | else |
||
317 | diff |= CT_DIFF(STATUS, a->ct_status != b->ct_status); |
||
318 | |||
319 | #undef CT_DIFF |
||
320 | #undef CT_DIFF_VAL |
||
321 | #undef CT_DIFF_ADDR |
||
322 | |||
323 | return diff; |
||
324 | } |
||
325 | |||
326 | static struct trans_tbl ct_attrs[] = { |
||
327 | __ADD(CT_ATTR_FAMILY, family) |
||
328 | __ADD(CT_ATTR_PROTO, proto) |
||
329 | __ADD(CT_ATTR_TCP_STATE, tcpstate) |
||
330 | __ADD(CT_ATTR_STATUS, status) |
||
331 | __ADD(CT_ATTR_TIMEOUT, timeout) |
||
332 | __ADD(CT_ATTR_MARK, mark) |
||
333 | __ADD(CT_ATTR_USE, use) |
||
334 | __ADD(CT_ATTR_ID, id) |
||
335 | __ADD(CT_ATTR_ORIG_SRC, origsrc) |
||
336 | __ADD(CT_ATTR_ORIG_DST, origdst) |
||
337 | __ADD(CT_ATTR_ORIG_SRC_PORT, origsrcport) |
||
338 | __ADD(CT_ATTR_ORIG_DST_PORT, origdstport) |
||
339 | __ADD(CT_ATTR_ORIG_ICMP_ID, origicmpid) |
||
340 | __ADD(CT_ATTR_ORIG_ICMP_TYPE, origicmptype) |
||
341 | __ADD(CT_ATTR_ORIG_ICMP_CODE, origicmpcode) |
||
342 | __ADD(CT_ATTR_ORIG_PACKETS, origpackets) |
||
343 | __ADD(CT_ATTR_ORIG_BYTES, origbytes) |
||
344 | __ADD(CT_ATTR_REPL_SRC, replysrc) |
||
345 | __ADD(CT_ATTR_REPL_DST, replydst) |
||
346 | __ADD(CT_ATTR_REPL_SRC_PORT, replysrcport) |
||
347 | __ADD(CT_ATTR_REPL_DST_PORT, replydstport) |
||
348 | __ADD(CT_ATTR_REPL_ICMP_ID, replyicmpid) |
||
349 | __ADD(CT_ATTR_REPL_ICMP_TYPE, replyicmptype) |
||
350 | __ADD(CT_ATTR_REPL_ICMP_CODE, replyicmpcode) |
||
351 | __ADD(CT_ATTR_REPL_PACKETS, replypackets) |
||
352 | __ADD(CT_ATTR_REPL_BYTES, replybytes) |
||
353 | }; |
||
354 | |||
355 | static char *ct_attrs2str(int attrs, char *buf, size_t len) |
||
356 | { |
||
357 | return __flags2str(attrs, buf, len, ct_attrs, ARRAY_SIZE(ct_attrs)); |
||
358 | } |
||
359 | |||
360 | /** |
||
361 | * @name Allocation/Freeing |
||
362 | * @{ |
||
363 | */ |
||
364 | |||
365 | struct nfnl_ct *nfnl_ct_alloc(void) |
||
366 | { |
||
367 | return (struct nfnl_ct *) nl_object_alloc(&ct_obj_ops); |
||
368 | } |
||
369 | |||
370 | void nfnl_ct_get(struct nfnl_ct *ct) |
||
371 | { |
||
372 | nl_object_get((struct nl_object *) ct); |
||
373 | } |
||
374 | |||
375 | void nfnl_ct_put(struct nfnl_ct *ct) |
||
376 | { |
||
377 | nl_object_put((struct nl_object *) ct); |
||
378 | } |
||
379 | |||
380 | /** @} */ |
||
381 | |||
382 | /** |
||
383 | * @name Attributes |
||
384 | * @{ |
||
385 | */ |
||
386 | |||
387 | void nfnl_ct_set_family(struct nfnl_ct *ct, uint8_t family) |
||
388 | { |
||
389 | ct->ct_family = family; |
||
390 | ct->ce_mask |= CT_ATTR_FAMILY; |
||
391 | } |
||
392 | |||
393 | uint8_t nfnl_ct_get_family(const struct nfnl_ct *ct) |
||
394 | { |
||
395 | if (ct->ce_mask & CT_ATTR_FAMILY) |
||
396 | return ct->ct_family; |
||
397 | else |
||
398 | return AF_UNSPEC; |
||
399 | } |
||
400 | |||
401 | void nfnl_ct_set_proto(struct nfnl_ct *ct, uint8_t proto) |
||
402 | { |
||
403 | ct->ct_proto = proto; |
||
404 | ct->ce_mask |= CT_ATTR_PROTO; |
||
405 | } |
||
406 | |||
407 | int nfnl_ct_test_proto(const struct nfnl_ct *ct) |
||
408 | { |
||
409 | return !!(ct->ce_mask & CT_ATTR_PROTO); |
||
410 | } |
||
411 | |||
412 | uint8_t nfnl_ct_get_proto(const struct nfnl_ct *ct) |
||
413 | { |
||
414 | return ct->ct_proto; |
||
415 | } |
||
416 | |||
417 | void nfnl_ct_set_tcp_state(struct nfnl_ct *ct, uint8_t state) |
||
418 | { |
||
419 | ct->ct_protoinfo.tcp.state = state; |
||
420 | ct->ce_mask |= CT_ATTR_TCP_STATE; |
||
421 | } |
||
422 | |||
423 | int nfnl_ct_test_tcp_state(const struct nfnl_ct *ct) |
||
424 | { |
||
425 | return !!(ct->ce_mask & CT_ATTR_TCP_STATE); |
||
426 | } |
||
427 | |||
428 | uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *ct) |
||
429 | { |
||
430 | return ct->ct_protoinfo.tcp.state; |
||
431 | } |
||
432 | |||
433 | static struct trans_tbl tcp_states[] = { |
||
434 | __ADD(TCP_CONNTRACK_NONE,NONE) |
||
435 | __ADD(TCP_CONNTRACK_SYN_SENT,SYN_SENT) |
||
436 | __ADD(TCP_CONNTRACK_SYN_RECV,SYN_RECV) |
||
437 | __ADD(TCP_CONNTRACK_ESTABLISHED,ESTABLISHED) |
||
438 | __ADD(TCP_CONNTRACK_FIN_WAIT,FIN_WAIT) |
||
439 | __ADD(TCP_CONNTRACK_CLOSE_WAIT,CLOSE_WAIT) |
||
440 | __ADD(TCP_CONNTRACK_LAST_ACK,LAST_ACK) |
||
441 | __ADD(TCP_CONNTRACK_TIME_WAIT,TIME_WAIT) |
||
442 | __ADD(TCP_CONNTRACK_CLOSE,CLOSE) |
||
443 | __ADD(TCP_CONNTRACK_LISTEN,LISTEN) |
||
444 | }; |
||
445 | |||
446 | char *nfnl_ct_tcp_state2str(uint8_t state, char *buf, size_t len) |
||
447 | { |
||
448 | return __type2str(state, buf, len, tcp_states, ARRAY_SIZE(tcp_states)); |
||
449 | } |
||
450 | |||
451 | int nfnl_ct_str2tcp_state(const char *name) |
||
452 | { |
||
453 | return __str2type(name, tcp_states, ARRAY_SIZE(tcp_states)); |
||
454 | } |
||
455 | |||
456 | void nfnl_ct_set_status(struct nfnl_ct *ct, uint32_t status) |
||
457 | { |
||
458 | ct->ct_status_mask |= status; |
||
459 | ct->ct_status |= status; |
||
460 | ct->ce_mask |= CT_ATTR_STATUS; |
||
461 | } |
||
462 | |||
463 | void nfnl_ct_unset_status(struct nfnl_ct *ct, uint32_t status) |
||
464 | { |
||
465 | ct->ct_status_mask |= status; |
||
466 | ct->ct_status &= ~status; |
||
467 | ct->ce_mask |= CT_ATTR_STATUS; |
||
468 | } |
||
469 | |||
470 | uint32_t nfnl_ct_get_status(const struct nfnl_ct *ct) |
||
471 | { |
||
472 | return ct->ct_status; |
||
473 | } |
||
474 | |||
475 | static struct trans_tbl status_flags[] = { |
||
476 | __ADD(IPS_EXPECTED, expected) |
||
477 | __ADD(IPS_SEEN_REPLY, seen_reply) |
||
478 | __ADD(IPS_ASSURED, assured) |
||
479 | __ADD(IPS_CONFIRMED, confirmed) |
||
480 | __ADD(IPS_SRC_NAT, snat) |
||
481 | __ADD(IPS_DST_NAT, dnat) |
||
482 | __ADD(IPS_SEQ_ADJUST, seqadjust) |
||
483 | __ADD(IPS_SRC_NAT_DONE, snat_done) |
||
484 | __ADD(IPS_DST_NAT_DONE, dnat_done) |
||
485 | __ADD(IPS_DYING, dying) |
||
486 | __ADD(IPS_FIXED_TIMEOUT, fixed_timeout) |
||
487 | }; |
||
488 | |||
489 | char * nfnl_ct_status2str(int flags, char *buf, size_t len) |
||
490 | { |
||
491 | return __flags2str(flags, buf, len, status_flags, |
||
492 | ARRAY_SIZE(status_flags)); |
||
493 | } |
||
494 | |||
495 | int nfnl_ct_str2status(const char *name) |
||
496 | { |
||
497 | return __str2flags(name, status_flags, ARRAY_SIZE(status_flags)); |
||
498 | } |
||
499 | |||
500 | void nfnl_ct_set_timeout(struct nfnl_ct *ct, uint32_t timeout) |
||
501 | { |
||
502 | ct->ct_timeout = timeout; |
||
503 | ct->ce_mask |= CT_ATTR_TIMEOUT; |
||
504 | } |
||
505 | |||
506 | int nfnl_ct_test_timeout(const struct nfnl_ct *ct) |
||
507 | { |
||
508 | return !!(ct->ce_mask & CT_ATTR_TIMEOUT); |
||
509 | } |
||
510 | |||
511 | uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *ct) |
||
512 | { |
||
513 | return ct->ct_timeout; |
||
514 | } |
||
515 | |||
516 | void nfnl_ct_set_mark(struct nfnl_ct *ct, uint32_t mark) |
||
517 | { |
||
518 | ct->ct_mark = mark; |
||
519 | ct->ce_mask |= CT_ATTR_MARK; |
||
520 | } |
||
521 | |||
522 | int nfnl_ct_test_mark(const struct nfnl_ct *ct) |
||
523 | { |
||
524 | return !!(ct->ce_mask & CT_ATTR_MARK); |
||
525 | } |
||
526 | |||
527 | uint32_t nfnl_ct_get_mark(const struct nfnl_ct *ct) |
||
528 | { |
||
529 | return ct->ct_mark; |
||
530 | } |
||
531 | |||
532 | void nfnl_ct_set_use(struct nfnl_ct *ct, uint32_t use) |
||
533 | { |
||
534 | ct->ct_use = use; |
||
535 | ct->ce_mask |= CT_ATTR_USE; |
||
536 | } |
||
537 | |||
538 | int nfnl_ct_test_use(const struct nfnl_ct *ct) |
||
539 | { |
||
540 | return !!(ct->ce_mask & CT_ATTR_USE); |
||
541 | } |
||
542 | |||
543 | uint32_t nfnl_ct_get_use(const struct nfnl_ct *ct) |
||
544 | { |
||
545 | return ct->ct_use; |
||
546 | } |
||
547 | |||
548 | void nfnl_ct_set_id(struct nfnl_ct *ct, uint32_t id) |
||
549 | { |
||
550 | ct->ct_id = id; |
||
551 | ct->ce_mask |= CT_ATTR_ID; |
||
552 | } |
||
553 | |||
554 | int nfnl_ct_test_id(const struct nfnl_ct *ct) |
||
555 | { |
||
556 | return !!(ct->ce_mask & CT_ATTR_ID); |
||
557 | } |
||
558 | |||
559 | uint32_t nfnl_ct_get_id(const struct nfnl_ct *ct) |
||
560 | { |
||
561 | return ct->ct_id; |
||
562 | } |
||
563 | |||
564 | static int ct_set_addr(struct nfnl_ct *ct, struct nl_addr *addr, |
||
565 | int attr, struct nl_addr ** ct_addr) |
||
566 | { |
||
567 | if (ct->ce_mask & CT_ATTR_FAMILY) { |
||
568 | if (addr->a_family != ct->ct_family) |
||
569 | return -NLE_AF_MISMATCH; |
||
570 | } else |
||
571 | nfnl_ct_set_family(ct, addr->a_family); |
||
572 | |||
573 | if (*ct_addr) |
||
574 | nl_addr_put(*ct_addr); |
||
575 | |||
576 | nl_addr_get(addr); |
||
577 | *ct_addr = addr; |
||
578 | ct->ce_mask |= attr; |
||
579 | |||
580 | return 0; |
||
581 | } |
||
582 | |||
583 | int nfnl_ct_set_src(struct nfnl_ct *ct, int repl, struct nl_addr *addr) |
||
584 | { |
||
585 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
586 | int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC; |
||
587 | return ct_set_addr(ct, addr, attr, &dir->src); |
||
588 | } |
||
589 | |||
590 | int nfnl_ct_set_dst(struct nfnl_ct *ct, int repl, struct nl_addr *addr) |
||
591 | { |
||
592 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
593 | int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST; |
||
594 | return ct_set_addr(ct, addr, attr, &dir->dst); |
||
595 | } |
||
596 | |||
597 | struct nl_addr *nfnl_ct_get_src(const struct nfnl_ct *ct, int repl) |
||
598 | { |
||
599 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
600 | int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC; |
||
601 | if (!(ct->ce_mask & attr)) |
||
602 | return NULL; |
||
603 | return dir->src; |
||
604 | } |
||
605 | |||
606 | struct nl_addr *nfnl_ct_get_dst(const struct nfnl_ct *ct, int repl) |
||
607 | { |
||
608 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
609 | int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST; |
||
610 | if (!(ct->ce_mask & attr)) |
||
611 | return NULL; |
||
612 | return dir->dst; |
||
613 | } |
||
614 | |||
615 | void nfnl_ct_set_src_port(struct nfnl_ct *ct, int repl, uint16_t port) |
||
616 | { |
||
617 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
618 | int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT; |
||
619 | |||
620 | dir->proto.port.src = port; |
||
621 | ct->ce_mask |= attr; |
||
622 | } |
||
623 | |||
624 | int nfnl_ct_test_src_port(const struct nfnl_ct *ct, int repl) |
||
625 | { |
||
626 | int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT; |
||
627 | return !!(ct->ce_mask & attr); |
||
628 | } |
||
629 | |||
630 | uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *ct, int repl) |
||
631 | { |
||
632 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
633 | |||
634 | return dir->proto.port.src; |
||
635 | } |
||
636 | |||
637 | void nfnl_ct_set_dst_port(struct nfnl_ct *ct, int repl, uint16_t port) |
||
638 | { |
||
639 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
640 | int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT; |
||
641 | |||
642 | dir->proto.port.dst = port; |
||
643 | ct->ce_mask |= attr; |
||
644 | } |
||
645 | |||
646 | int nfnl_ct_test_dst_port(const struct nfnl_ct *ct, int repl) |
||
647 | { |
||
648 | int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT; |
||
649 | return !!(ct->ce_mask & attr); |
||
650 | } |
||
651 | |||
652 | uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *ct, int repl) |
||
653 | { |
||
654 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
655 | |||
656 | return dir->proto.port.dst; |
||
657 | } |
||
658 | |||
659 | void nfnl_ct_set_icmp_id(struct nfnl_ct *ct, int repl, uint16_t id) |
||
660 | { |
||
661 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
662 | int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID; |
||
663 | |||
664 | dir->proto.icmp.id = id; |
||
665 | ct->ce_mask |= attr; |
||
666 | } |
||
667 | |||
668 | int nfnl_ct_test_icmp_id(const struct nfnl_ct *ct, int repl) |
||
669 | { |
||
670 | int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID; |
||
671 | return !!(ct->ce_mask & attr); |
||
672 | } |
||
673 | |||
674 | uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *ct, int repl) |
||
675 | { |
||
676 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
677 | |||
678 | return dir->proto.icmp.id; |
||
679 | } |
||
680 | |||
681 | void nfnl_ct_set_icmp_type(struct nfnl_ct *ct, int repl, uint8_t type) |
||
682 | { |
||
683 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
684 | int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE; |
||
685 | |||
686 | dir->proto.icmp.type = type; |
||
687 | ct->ce_mask |= attr; |
||
688 | } |
||
689 | |||
690 | int nfnl_ct_test_icmp_type(const struct nfnl_ct *ct, int repl) |
||
691 | { |
||
692 | int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE; |
||
693 | return !!(ct->ce_mask & attr); |
||
694 | } |
||
695 | |||
696 | uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *ct, int repl) |
||
697 | { |
||
698 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
699 | |||
700 | return dir->proto.icmp.type; |
||
701 | } |
||
702 | |||
703 | void nfnl_ct_set_icmp_code(struct nfnl_ct *ct, int repl, uint8_t code) |
||
704 | { |
||
705 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
706 | int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE; |
||
707 | |||
708 | dir->proto.icmp.code = code; |
||
709 | ct->ce_mask |= attr; |
||
710 | } |
||
711 | |||
712 | int nfnl_ct_test_icmp_code(const struct nfnl_ct *ct, int repl) |
||
713 | { |
||
714 | int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE; |
||
715 | return !!(ct->ce_mask & attr); |
||
716 | } |
||
717 | |||
718 | uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *ct, int repl) |
||
719 | { |
||
720 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
721 | |||
722 | return dir->proto.icmp.code; |
||
723 | } |
||
724 | |||
725 | void nfnl_ct_set_packets(struct nfnl_ct *ct, int repl, uint64_t packets) |
||
726 | { |
||
727 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
728 | int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS; |
||
729 | |||
730 | dir->packets = packets; |
||
731 | ct->ce_mask |= attr; |
||
732 | } |
||
733 | |||
734 | int nfnl_ct_test_packets(const struct nfnl_ct *ct, int repl) |
||
735 | { |
||
736 | int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS; |
||
737 | return !!(ct->ce_mask & attr); |
||
738 | } |
||
739 | |||
740 | uint64_t nfnl_ct_get_packets(const struct nfnl_ct *ct, int repl) |
||
741 | { |
||
742 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
743 | |||
744 | return dir->packets; |
||
745 | } |
||
746 | |||
747 | void nfnl_ct_set_bytes(struct nfnl_ct *ct, int repl, uint64_t bytes) |
||
748 | { |
||
749 | struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
750 | int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES; |
||
751 | |||
752 | dir->bytes = bytes; |
||
753 | ct->ce_mask |= attr; |
||
754 | } |
||
755 | |||
756 | int nfnl_ct_test_bytes(const struct nfnl_ct *ct, int repl) |
||
757 | { |
||
758 | int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES; |
||
759 | return !!(ct->ce_mask & attr); |
||
760 | } |
||
761 | |||
762 | uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *ct, int repl) |
||
763 | { |
||
764 | const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; |
||
765 | |||
766 | return dir->bytes; |
||
767 | } |
||
768 | |||
769 | /** @} */ |
||
770 | |||
771 | struct nl_object_ops ct_obj_ops = { |
||
772 | .oo_name = "netfilter/ct", |
||
773 | .oo_size = sizeof(struct nfnl_ct), |
||
774 | .oo_free_data = ct_free_data, |
||
775 | .oo_clone = ct_clone, |
||
776 | .oo_dump = { |
||
777 | [NL_DUMP_LINE] = ct_dump_line, |
||
778 | [NL_DUMP_DETAILS] = ct_dump_details, |
||
779 | [NL_DUMP_STATS] = ct_dump_stats, |
||
780 | }, |
||
781 | .oo_compare = ct_compare, |
||
782 | .oo_attrs2str = ct_attrs2str, |
||
783 | }; |
||
784 | |||
785 | /** @} */ |