1/* 2 * (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * (C) 2012 by Intra2net AG <http://www.intra2net.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 * 19 * Note: 20 * Yes, portions of this code has been stolen from iptables ;) 21 * Special thanks to the the Netfilter Core Team. 22 * Thanks to Javier de Miguel Rodriguez <jmiguel at talika.eii.us.es> 23 * for introducing me to advanced firewalling stuff. 24 * 25 * --pablo 13/04/2005 26 * 27 * 2005-04-16 Harald Welte <laforge@netfilter.org>: 28 * Add support for conntrack accounting and conntrack mark 29 * 2005-06-23 Harald Welte <laforge@netfilter.org>: 30 * Add support for expect creation 31 * 2005-09-24 Harald Welte <laforge@netfilter.org>: 32 * Remove remaints of "-A" 33 * 2007-04-22 Pablo Neira Ayuso <pablo@netfilter.org>: 34 * Ported to the new libnetfilter_conntrack API 35 * 2008-04-13 Pablo Neira Ayuso <pablo@netfilter.org>: 36 * Way more flexible update and delete operations 37 * 38 * Part of this code has been funded by Sophos Astaro <http://www.sophos.com> 39 */ 40 41#include "conntrack.h" 42 43#include <stdio.h> 44#include <getopt.h> 45#include <stdlib.h> 46#include <stdarg.h> 47#include <errno.h> 48#include <unistd.h> 49#include <netinet/in.h> 50#include <sys/types.h> 51#include <sys/socket.h> 52#include <sys/time.h> 53#include <time.h> 54#ifdef HAVE_ARPA_INET_H 55#include <arpa/inet.h> 56#endif 57#include <signal.h> 58#include <string.h> 59#include <netdb.h> 60#include <sys/stat.h> 61#include <fcntl.h> 62#include <libmnl/libmnl.h> 63#include <libnetfilter_conntrack/libnetfilter_conntrack.h> 64 65struct u32_mask { 66 uint32_t value; 67 uint32_t mask; 68}; 69 70/* These are the template objects that are used to send commands. */ 71static struct { 72 struct nf_conntrack *ct; 73 struct nf_expect *exp; 74 /* Expectations require the expectation tuple and the mask. */ 75 struct nf_conntrack *exptuple, *mask; 76 77 /* Allows filtering/setting specific bits in the ctmark */ 78 struct u32_mask mark; 79 80 /* Allow to filter by mark from kernel-space. */ 81 struct nfct_filter_dump_mark filter_mark_kernel; 82} tmpl; 83 84static int alloc_tmpl_objects(void) 85{ 86 tmpl.ct = nfct_new(); 87 tmpl.exptuple = nfct_new(); 88 tmpl.mask = nfct_new(); 89 tmpl.exp = nfexp_new(); 90 91 memset(&tmpl.mark, 0, sizeof(tmpl.mark)); 92 93 return tmpl.ct != NULL && tmpl.exptuple != NULL && 94 tmpl.mask != NULL && tmpl.exp != NULL; 95} 96 97static void free_tmpl_objects(void) 98{ 99 if (tmpl.ct) 100 nfct_destroy(tmpl.ct); 101 if (tmpl.exptuple) 102 nfct_destroy(tmpl.exptuple); 103 if (tmpl.mask) 104 nfct_destroy(tmpl.mask); 105 if (tmpl.exp) 106 nfexp_destroy(tmpl.exp); 107} 108 109enum ct_command { 110 CT_NONE = 0, 111 112 CT_LIST_BIT = 0, 113 CT_LIST = (1 << CT_LIST_BIT), 114 115 CT_CREATE_BIT = 1, 116 CT_CREATE = (1 << CT_CREATE_BIT), 117 118 CT_UPDATE_BIT = 2, 119 CT_UPDATE = (1 << CT_UPDATE_BIT), 120 121 CT_DELETE_BIT = 3, 122 CT_DELETE = (1 << CT_DELETE_BIT), 123 124 CT_GET_BIT = 4, 125 CT_GET = (1 << CT_GET_BIT), 126 127 CT_FLUSH_BIT = 5, 128 CT_FLUSH = (1 << CT_FLUSH_BIT), 129 130 CT_EVENT_BIT = 6, 131 CT_EVENT = (1 << CT_EVENT_BIT), 132 133 CT_VERSION_BIT = 7, 134 CT_VERSION = (1 << CT_VERSION_BIT), 135 136 CT_HELP_BIT = 8, 137 CT_HELP = (1 << CT_HELP_BIT), 138 139 EXP_LIST_BIT = 9, 140 EXP_LIST = (1 << EXP_LIST_BIT), 141 142 EXP_CREATE_BIT = 10, 143 EXP_CREATE = (1 << EXP_CREATE_BIT), 144 145 EXP_DELETE_BIT = 11, 146 EXP_DELETE = (1 << EXP_DELETE_BIT), 147 148 EXP_GET_BIT = 12, 149 EXP_GET = (1 << EXP_GET_BIT), 150 151 EXP_FLUSH_BIT = 13, 152 EXP_FLUSH = (1 << EXP_FLUSH_BIT), 153 154 EXP_EVENT_BIT = 14, 155 EXP_EVENT = (1 << EXP_EVENT_BIT), 156 157 CT_COUNT_BIT = 15, 158 CT_COUNT = (1 << CT_COUNT_BIT), 159 160 EXP_COUNT_BIT = 16, 161 EXP_COUNT = (1 << EXP_COUNT_BIT), 162 163 CT_STATS_BIT = 17, 164 CT_STATS = (1 << CT_STATS_BIT), 165 166 EXP_STATS_BIT = 18, 167 EXP_STATS = (1 << EXP_STATS_BIT), 168}; 169/* If you add a new command, you have to update NUMBER_OF_CMD in conntrack.h */ 170 171enum ct_options { 172 CT_OPT_ORIG_SRC_BIT = 0, 173 CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), 174 175 CT_OPT_ORIG_DST_BIT = 1, 176 CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), 177 178 CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), 179 180 CT_OPT_REPL_SRC_BIT = 2, 181 CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), 182 183 CT_OPT_REPL_DST_BIT = 3, 184 CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), 185 186 CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), 187 188 CT_OPT_PROTO_BIT = 4, 189 CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), 190 191 CT_OPT_TUPLE_ORIG = (CT_OPT_ORIG | CT_OPT_PROTO), 192 CT_OPT_TUPLE_REPL = (CT_OPT_REPL | CT_OPT_PROTO), 193 194 CT_OPT_TIMEOUT_BIT = 5, 195 CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), 196 197 CT_OPT_STATUS_BIT = 6, 198 CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), 199 200 CT_OPT_ZERO_BIT = 7, 201 CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), 202 203 CT_OPT_EVENT_MASK_BIT = 8, 204 CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), 205 206 CT_OPT_EXP_SRC_BIT = 9, 207 CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), 208 209 CT_OPT_EXP_DST_BIT = 10, 210 CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), 211 212 CT_OPT_MASK_SRC_BIT = 11, 213 CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), 214 215 CT_OPT_MASK_DST_BIT = 12, 216 CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), 217 218 CT_OPT_NATRANGE_BIT = 13, 219 CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), 220 221 CT_OPT_MARK_BIT = 14, 222 CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), 223 224 CT_OPT_ID_BIT = 15, 225 CT_OPT_ID = (1 << CT_OPT_ID_BIT), 226 227 CT_OPT_FAMILY_BIT = 16, 228 CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), 229 230 CT_OPT_SRC_NAT_BIT = 17, 231 CT_OPT_SRC_NAT = (1 << CT_OPT_SRC_NAT_BIT), 232 233 CT_OPT_DST_NAT_BIT = 18, 234 CT_OPT_DST_NAT = (1 << CT_OPT_DST_NAT_BIT), 235 236 CT_OPT_OUTPUT_BIT = 19, 237 CT_OPT_OUTPUT = (1 << CT_OPT_OUTPUT_BIT), 238 239 CT_OPT_SECMARK_BIT = 20, 240 CT_OPT_SECMARK = (1 << CT_OPT_SECMARK_BIT), 241 242 CT_OPT_BUFFERSIZE_BIT = 21, 243 CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT), 244 245 CT_OPT_ANY_NAT_BIT = 22, 246 CT_OPT_ANY_NAT = (1 << CT_OPT_ANY_NAT_BIT), 247 248 CT_OPT_ZONE_BIT = 23, 249 CT_OPT_ZONE = (1 << CT_OPT_ZONE_BIT), 250}; 251/* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ 252 253/* Update this mask to allow to filter based on new options. */ 254#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | \ 255 CT_OPT_MARK | CT_OPT_SECMARK | CT_OPT_STATUS | \ 256 CT_OPT_ID | CT_OPT_ZONE) 257 258static const char *optflags[NUMBER_OF_OPT] = { 259 [CT_OPT_ORIG_SRC_BIT] = "src", 260 [CT_OPT_ORIG_DST_BIT] = "dst", 261 [CT_OPT_REPL_SRC_BIT] = "reply-src", 262 [CT_OPT_REPL_DST_BIT] = "reply-dst", 263 [CT_OPT_PROTO_BIT] = "protonum", 264 [CT_OPT_TIMEOUT_BIT] = "timeout", 265 [CT_OPT_STATUS_BIT] = "status", 266 [CT_OPT_ZERO_BIT] = "zero", 267 [CT_OPT_EVENT_MASK_BIT] = "event-mask", 268 [CT_OPT_EXP_SRC_BIT] = "tuple-src", 269 [CT_OPT_EXP_DST_BIT] = "tuple-dst", 270 [CT_OPT_MASK_SRC_BIT] = "mask-src", 271 [CT_OPT_MASK_DST_BIT] = "mask-dst", 272 [CT_OPT_NATRANGE_BIT] = "nat-range", 273 [CT_OPT_MARK_BIT] = "mark", 274 [CT_OPT_ID_BIT] = "id", 275 [CT_OPT_FAMILY_BIT] = "family", 276 [CT_OPT_SRC_NAT_BIT] = "src-nat", 277 [CT_OPT_DST_NAT_BIT] = "dst-nat", 278 [CT_OPT_OUTPUT_BIT] = "output", 279 [CT_OPT_SECMARK_BIT] = "secmark", 280 [CT_OPT_BUFFERSIZE_BIT] = "buffer-size", 281 [CT_OPT_ANY_NAT_BIT] = "any-nat", 282 [CT_OPT_ZONE_BIT] = "zone", 283}; 284 285static struct option original_opts[] = { 286 {"dump", 2, 0, 'L'}, 287 {"create", 2, 0, 'I'}, 288 {"delete", 2, 0, 'D'}, 289 {"update", 2, 0, 'U'}, 290 {"get", 2, 0, 'G'}, 291 {"flush", 2, 0, 'F'}, 292 {"event", 2, 0, 'E'}, 293 {"counter", 2, 0, 'C'}, 294 {"stats", 0, 0, 'S'}, 295 {"version", 0, 0, 'V'}, 296 {"help", 0, 0, 'h'}, 297 {"orig-src", 1, 0, 's'}, 298 {"src", 1, 0, 's'}, 299 {"orig-dst", 1, 0, 'd'}, 300 {"dst", 1, 0, 'd'}, 301 {"reply-src", 1, 0, 'r'}, 302 {"reply-dst", 1, 0, 'q'}, 303 {"protonum", 1, 0, 'p'}, 304 {"timeout", 1, 0, 't'}, 305 {"status", 1, 0, 'u'}, 306 {"zero", 0, 0, 'z'}, 307 {"event-mask", 1, 0, 'e'}, 308 {"tuple-src", 1, 0, '['}, 309 {"tuple-dst", 1, 0, ']'}, 310 {"mask-src", 1, 0, '{'}, 311 {"mask-dst", 1, 0, '}'}, 312 {"nat-range", 1, 0, 'a'}, /* deprecated */ 313 {"mark", 1, 0, 'm'}, 314 {"secmark", 1, 0, 'c'}, 315 {"id", 2, 0, 'i'}, /* deprecated */ 316 {"family", 1, 0, 'f'}, 317 {"src-nat", 2, 0, 'n'}, 318 {"dst-nat", 2, 0, 'g'}, 319 {"output", 1, 0, 'o'}, 320 {"buffer-size", 1, 0, 'b'}, 321 {"any-nat", 2, 0, 'j'}, 322 {"zone", 1, 0, 'w'}, 323 {0, 0, 0, 0} 324}; 325 326static const char *getopt_str = "L::I::U::D::G::E::F::hVs:d:r:q:" 327 "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" 328 "g::c:b:C::Sj::w:"; 329 330/* Table of legal combinations of commands and options. If any of the 331 * given commands make an option legal, that option is legal (applies to 332 * CMD_LIST and CMD_ZERO only). 333 * Key: 334 * 0 illegal 335 * 1 compulsory 336 * 2 optional 337 * 3 undecided, see flag combination checkings in generic_opt_check() 338 */ 339 340static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = 341/* Well, it's better than "Re: Linux vs FreeBSD" */ 342{ 343 /* s d r q p t u z e [ ] { } a m i f n g o c b j w*/ 344/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2}, 345/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2}, 346/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0}, 347/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2}, 348/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0}, 349/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 350/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2}, 351/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 352/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 353/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0}, 354/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}, 355/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 356/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 357/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 358/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0}, 359/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 360/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 361/*CT_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 362/*EXP_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 363}; 364 365static const int cmd2type[][2] = { 366 ['L'] = { CT_LIST, EXP_LIST }, 367 ['I'] = { CT_CREATE, EXP_CREATE }, 368 ['D'] = { CT_DELETE, EXP_DELETE }, 369 ['G'] = { CT_GET, EXP_GET }, 370 ['F'] = { CT_FLUSH, EXP_FLUSH }, 371 ['E'] = { CT_EVENT, EXP_EVENT }, 372 ['V'] = { CT_VERSION, CT_VERSION }, 373 ['h'] = { CT_HELP, CT_HELP }, 374 ['C'] = { CT_COUNT, EXP_COUNT }, 375 ['S'] = { CT_STATS, EXP_STATS }, 376}; 377 378static const int opt2type[] = { 379 ['s'] = CT_OPT_ORIG_SRC, 380 ['d'] = CT_OPT_ORIG_DST, 381 ['r'] = CT_OPT_REPL_SRC, 382 ['q'] = CT_OPT_REPL_DST, 383 ['{'] = CT_OPT_MASK_SRC, 384 ['}'] = CT_OPT_MASK_DST, 385 ['['] = CT_OPT_EXP_SRC, 386 [']'] = CT_OPT_EXP_DST, 387 ['n'] = CT_OPT_SRC_NAT, 388 ['g'] = CT_OPT_DST_NAT, 389 ['m'] = CT_OPT_MARK, 390 ['c'] = CT_OPT_SECMARK, 391 ['i'] = CT_OPT_ID, 392 ['j'] = CT_OPT_ANY_NAT, 393 ['w'] = CT_OPT_ZONE, 394}; 395 396static const int opt2family_attr[][2] = { 397 ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, 398 ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, 399 ['r'] = { ATTR_REPL_IPV4_SRC, ATTR_REPL_IPV6_SRC }, 400 ['q'] = { ATTR_REPL_IPV4_DST, ATTR_REPL_IPV6_DST }, 401 ['{'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, 402 ['}'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, 403 ['['] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, 404 [']'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, 405}; 406 407static const int opt2attr[] = { 408 ['s'] = ATTR_ORIG_L3PROTO, 409 ['d'] = ATTR_ORIG_L3PROTO, 410 ['r'] = ATTR_REPL_L3PROTO, 411 ['q'] = ATTR_REPL_L3PROTO, 412 ['m'] = ATTR_MARK, 413 ['c'] = ATTR_SECMARK, 414 ['i'] = ATTR_ID, 415 ['w'] = ATTR_ZONE, 416}; 417 418static char exit_msg[NUMBER_OF_CMD][64] = { 419 [CT_LIST_BIT] = "%d flow entries have been shown.\n", 420 [CT_CREATE_BIT] = "%d flow entries have been created.\n", 421 [CT_UPDATE_BIT] = "%d flow entries have been updated.\n", 422 [CT_DELETE_BIT] = "%d flow entries have been deleted.\n", 423 [CT_GET_BIT] = "%d flow entries have been shown.\n", 424 [CT_EVENT_BIT] = "%d flow events have been shown.\n", 425 [EXP_LIST_BIT] = "%d expectations have been shown.\n", 426 [EXP_DELETE_BIT] = "%d expectations have been shown.\n", 427}; 428 429static const char usage_commands[] = 430 "Commands:\n" 431 " -L [table] [options]\t\tList conntrack or expectation table\n" 432 " -G [table] parameters\t\tGet conntrack or expectation\n" 433 " -D [table] parameters\t\tDelete conntrack or expectation\n" 434 " -I [table] parameters\t\tCreate a conntrack or expectation\n" 435 " -U [table] parameters\t\tUpdate a conntrack\n" 436 " -E [table] [options]\t\tShow events\n" 437 " -F [table]\t\t\tFlush table\n" 438 " -C [table]\t\t\tShow counter\n" 439 " -S\t\t\t\tShow statistics\n"; 440 441static const char usage_tables[] = 442 "Tables: conntrack, expect\n"; 443 444static const char usage_conntrack_parameters[] = 445 "Conntrack parameters and options:\n" 446 " -n, --src-nat ip\t\t\tsource NAT ip\n" 447 " -g, --dst-nat ip\t\t\tdestination NAT ip\n" 448 " -j, --any-nat ip\t\t\tsource or destination NAT ip\n" 449 " -m, --mark mark\t\t\tSet mark\n" 450 " -c, --secmark secmark\t\t\tSet selinux secmark\n" 451 " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" 452 " -z, --zero \t\t\t\tZero counters while listing\n" 453 " -o, --output type[,...]\t\tOutput format, eg. xml\n"; 454 455static const char usage_expectation_parameters[] = 456 "Expectation parameters and options:\n" 457 " --tuple-src ip\tSource address in expect tuple\n" 458 " --tuple-dst ip\tDestination address in expect tuple\n" 459 " --mask-src ip\t\tSource mask address\n" 460 " --mask-dst ip\t\tDestination mask address\n"; 461 462static const char usage_parameters[] = 463 "Common parameters and options:\n" 464 " -s, --orig-src ip\t\tSource address from original direction\n" 465 " -d, --orig-dst ip\t\tDestination address from original direction\n" 466 " -r, --reply-src ip\t\tSource addres from reply direction\n" 467 " -q, --reply-dst ip\t\tDestination address from reply direction\n" 468 " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" 469 " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" 470 " -t, --timeout timeout\t\tSet timeout\n" 471 " -u, --status status\t\tSet status, eg. ASSURED\n" 472 " -w, --zone value\t\tSet conntrack zone\n" 473 " -b, --buffer-size\t\tNetlink socket buffer size\n" 474 ; 475 476#define OPTION_OFFSET 256 477 478static struct nfct_handle *cth, *ith; 479static struct option *opts = original_opts; 480static unsigned int global_option_offset = 0; 481 482#define ADDR_VALID_FLAGS_MAX 2 483static unsigned int addr_valid_flags[ADDR_VALID_FLAGS_MAX] = { 484 CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST, 485 CT_OPT_REPL_SRC | CT_OPT_REPL_DST, 486}; 487 488static LIST_HEAD(proto_list); 489 490static unsigned int options; 491 492void register_proto(struct ctproto_handler *h) 493{ 494 if (strcmp(h->version, VERSION) != 0) { 495 fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", 496 h->name, h->version, VERSION); 497 exit(1); 498 } 499 list_add(&h->head, &proto_list); 500} 501 502extern struct ctproto_handler ct_proto_unknown; 503 504static struct ctproto_handler *findproto(char *name, int *pnum) 505{ 506 struct ctproto_handler *cur; 507 struct protoent *pent; 508 int protonum; 509 510 /* is it in the list of supported protocol? */ 511 list_for_each_entry(cur, &proto_list, head) { 512 if (strcmp(cur->name, name) == 0) { 513 *pnum = cur->protonum; 514 return cur; 515 } 516 } 517 /* using the protocol name for an unsupported protocol? */ 518 if ((pent = getprotobyname(name))) { 519 *pnum = pent->p_proto; 520 return &ct_proto_unknown; 521 } 522 /* using a protocol number? */ 523 protonum = atoi(name); 524 if (protonum > 0 && protonum <= IPPROTO_MAX) { 525 /* try lookup by number, perhaps this protocol is supported */ 526 list_for_each_entry(cur, &proto_list, head) { 527 if (cur->protonum == protonum) { 528 *pnum = protonum; 529 return cur; 530 } 531 } 532 *pnum = protonum; 533 return &ct_proto_unknown; 534 } 535 536 return NULL; 537} 538 539static void 540extension_help(struct ctproto_handler *h, int protonum) 541{ 542 const char *name; 543 544 if (h == &ct_proto_unknown) { 545 struct protoent *pent; 546 547 pent = getprotobynumber(protonum); 548 if (!pent) 549 name = h->name; 550 else 551 name = pent->p_name; 552 } else { 553 name = h->name; 554 } 555 556 fprintf(stdout, "Proto `%s' help:\n", name); 557 h->help(); 558} 559 560static void __attribute__((noreturn)) 561exit_tryhelp(int status) 562{ 563 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", 564 PROGNAME, PROGNAME); 565 exit(status); 566} 567 568static void free_options(void) 569{ 570 if (opts != original_opts) { 571 free(opts); 572 opts = original_opts; 573 global_option_offset = 0; 574 } 575} 576 577void __attribute__((noreturn)) 578exit_error(enum exittype status, const char *msg, ...) 579{ 580 va_list args; 581 582 free_options(); 583 va_start(args, msg); 584 fprintf(stderr,"%s v%s (conntrack-tools): ", PROGNAME, VERSION); 585 vfprintf(stderr, msg, args); 586 fprintf(stderr, "\n"); 587 va_end(args); 588 if (status == PARAMETER_PROBLEM) 589 exit_tryhelp(status); 590 /* release template objects that were allocated in the setup stage. */ 591 free_tmpl_objects(); 592 exit(status); 593} 594 595static int bit2cmd(int command) 596{ 597 int i; 598 599 for (i = 0; i < NUMBER_OF_CMD; i++) 600 if (command & (1<<i)) 601 break; 602 603 return i; 604} 605 606int generic_opt_check(int local_options, int num_opts, 607 char *optset, const char *optflg[], 608 unsigned int *coupled_flags, int coupled_flags_size, 609 int *partial) 610{ 611 int i, matching = -1, special_case = 0; 612 613 for (i = 0; i < num_opts; i++) { 614 if (!(local_options & (1<<i))) { 615 if (optset[i] == 1) 616 exit_error(PARAMETER_PROBLEM, 617 "You need to supply the " 618 "`--%s' option for this " 619 "command", optflg[i]); 620 } else { 621 if (optset[i] == 0) 622 exit_error(PARAMETER_PROBLEM, "Illegal " 623 "option `--%s' with this " 624 "command", optflg[i]); 625 } 626 if (optset[i] == 3) 627 special_case = 1; 628 } 629 630 /* no weird flags combinations, leave */ 631 if (!special_case || coupled_flags == NULL) 632 return 1; 633 634 *partial = -1; 635 for (i=0; i<coupled_flags_size; i++) { 636 /* we look for an exact matching to ensure this is correct */ 637 if ((local_options & coupled_flags[i]) == coupled_flags[i]) { 638 matching = i; 639 break; 640 } 641 /* ... otherwise look for the first partial matching */ 642 if ((local_options & coupled_flags[i]) && *partial < 0) { 643 *partial = i; 644 } 645 } 646 647 /* we found an exact matching, game over */ 648 if (matching >= 0) 649 return 1; 650 651 /* report a partial matching to suggest something */ 652 return 0; 653} 654 655static struct option * 656merge_options(struct option *oldopts, const struct option *newopts, 657 unsigned int *option_offset) 658{ 659 unsigned int num_old, num_new, i; 660 struct option *merge; 661 662 for (num_old = 0; oldopts[num_old].name; num_old++); 663 for (num_new = 0; newopts[num_new].name; num_new++); 664 665 global_option_offset += OPTION_OFFSET; 666 *option_offset = global_option_offset; 667 668 merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); 669 if (merge == NULL) 670 return NULL; 671 672 memcpy(merge, oldopts, num_old * sizeof(struct option)); 673 for (i = 0; i < num_new; i++) { 674 merge[num_old + i] = newopts[i]; 675 merge[num_old + i].val += *option_offset; 676 } 677 memset(merge + num_old + num_new, 0, sizeof(struct option)); 678 679 return merge; 680} 681 682/* From linux/errno.h */ 683#define ENOTSUPP 524 /* Operation is not supported */ 684 685/* Translates errno numbers into more human-readable form than strerror. */ 686static const char * 687err2str(int err, enum ct_command command) 688{ 689 unsigned int i; 690 struct table_struct { 691 enum ct_command act; 692 int err; 693 const char *message; 694 } table [] = 695 { { CT_LIST, ENOTSUPP, "function not implemented" }, 696 { 0xFFFF, EINVAL, "invalid parameters" }, 697 { CT_CREATE, EEXIST, "Such conntrack exists, try -U to update" }, 698 { CT_CREATE|CT_GET|CT_DELETE, ENOENT, 699 "such conntrack doesn't exist" }, 700 { CT_CREATE|CT_GET, ENOMEM, "not enough memory" }, 701 { CT_GET, EAFNOSUPPORT, "protocol not supported" }, 702 { CT_CREATE, ETIME, "conntrack has expired" }, 703 { EXP_CREATE, ENOENT, "master conntrack not found" }, 704 { EXP_CREATE, EINVAL, "invalid parameters" }, 705 { ~0U, EPERM, "sorry, you must be root or get " 706 "CAP_NET_ADMIN capability to do this"} 707 }; 708 709 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { 710 if ((table[i].act & command) && table[i].err == err) 711 return table[i].message; 712 } 713 714 return strerror(err); 715} 716 717static int mark_cmp(const struct u32_mask *m, const struct nf_conntrack *ct) 718{ 719 return nfct_attr_is_set(ct, ATTR_MARK) && 720 (nfct_get_attr_u32(ct, ATTR_MARK) & m->mask) == m->value; 721} 722 723#define PARSE_STATUS 0 724#define PARSE_EVENT 1 725#define PARSE_OUTPUT 2 726#define PARSE_MAX 3 727 728enum { 729 _O_XML = (1 << 0), 730 _O_EXT = (1 << 1), 731 _O_TMS = (1 << 2), 732 _O_ID = (1 << 3), 733 _O_KTMS = (1 << 4), 734}; 735 736enum { 737 CT_EVENT_F_NEW = (1 << 0), 738 CT_EVENT_F_UPD = (1 << 1), 739 CT_EVENT_F_DEL = (1 << 2), 740 CT_EVENT_F_ALL = CT_EVENT_F_NEW | CT_EVENT_F_UPD | CT_EVENT_F_DEL, 741}; 742 743static struct parse_parameter { 744 const char *parameter[6]; 745 size_t size; 746 unsigned int value[6]; 747} parse_array[PARSE_MAX] = { 748 { {"ASSURED", "SEEN_REPLY", "UNSET", "FIXED_TIMEOUT", "EXPECTED"}, 5, 749 { IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT, IPS_EXPECTED} }, 750 { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, 751 { CT_EVENT_F_ALL, CT_EVENT_F_NEW, CT_EVENT_F_UPD, CT_EVENT_F_DEL } }, 752 { {"xml", "extended", "timestamp", "id", "ktimestamp"}, 5, 753 { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS }, 754 }, 755}; 756 757static int 758do_parse_parameter(const char *str, size_t str_length, unsigned int *value, 759 int parse_type) 760{ 761 size_t i; 762 int ret = 0; 763 struct parse_parameter *p = &parse_array[parse_type]; 764 765 if (strncasecmp(str, "SRC_NAT", str_length) == 0) { 766 fprintf(stderr, "WARNING: ignoring SRC_NAT, " 767 "use --src-nat instead\n"); 768 return 1; 769 } 770 771 if (strncasecmp(str, "DST_NAT", str_length) == 0) { 772 fprintf(stderr, "WARNING: ignoring DST_NAT, " 773 "use --dst-nat instead\n"); 774 return 1; 775 } 776 777 for (i = 0; i < p->size; i++) 778 if (strncasecmp(str, p->parameter[i], str_length) == 0) { 779 *value |= p->value[i]; 780 ret = 1; 781 break; 782 } 783 784 return ret; 785} 786 787static void 788parse_parameter(const char *arg, unsigned int *status, int parse_type) 789{ 790 const char *comma; 791 792 while ((comma = strchr(arg, ',')) != NULL) { 793 if (comma == arg 794 || !do_parse_parameter(arg, comma-arg, status, parse_type)) 795 exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg); 796 arg = comma+1; 797 } 798 799 if (strlen(arg) == 0 800 || !do_parse_parameter(arg, strlen(arg), status, parse_type)) 801 exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); 802} 803 804static void 805parse_u32_mask(const char *arg, struct u32_mask *m) 806{ 807 char *end; 808 809 m->value = (uint32_t) strtoul(arg, &end, 0); 810 811 if (*end == '/') 812 m->mask = (uint32_t) strtoul(end+1, NULL, 0); 813 else 814 m->mask = ~0; 815} 816 817static void 818add_command(unsigned int *cmd, const int newcmd) 819{ 820 if (*cmd) 821 exit_error(PARAMETER_PROBLEM, "Invalid commands combination"); 822 *cmd |= newcmd; 823} 824 825static unsigned int 826check_type(int argc, char *argv[]) 827{ 828 char *table = NULL; 829 830 /* Nasty bug or feature in getopt_long ? 831 * It seems that it behaves badly with optional arguments. 832 * Fortunately, I just stole the fix from iptables ;) */ 833 if (optarg) 834 return 0; 835 else if (optind < argc && argv[optind][0] != '-' 836 && argv[optind][0] != '!') 837 table = argv[optind++]; 838 839 if (!table) 840 return 0; 841 842 if (strncmp("expect", table, strlen(table)) == 0) 843 return 1; 844 else if (strncmp("conntrack", table, strlen(table)) == 0) 845 return 0; 846 else 847 exit_error(PARAMETER_PROBLEM, "unknown type `%s'", table); 848 849 return 0; 850} 851 852static void set_family(int *family, int new) 853{ 854 if (*family == AF_UNSPEC) 855 *family = new; 856 else if (*family != new) 857 exit_error(PARAMETER_PROBLEM, "mismatched address family"); 858} 859 860struct addr_parse { 861 struct in_addr addr; 862 struct in6_addr addr6; 863 unsigned int family; 864}; 865 866static int 867parse_inetaddr(const char *cp, struct addr_parse *parse) 868{ 869 if (inet_aton(cp, &parse->addr)) 870 return AF_INET; 871#ifdef HAVE_INET_PTON_IPV6 872 else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) 873 return AF_INET6; 874#endif 875 return AF_UNSPEC; 876} 877 878union ct_address { 879 uint32_t v4; 880 uint32_t v6[4]; 881}; 882 883static int 884parse_addr(const char *cp, union ct_address *address) 885{ 886 struct addr_parse parse; 887 int ret; 888 889 if ((ret = parse_inetaddr(cp, &parse)) == AF_INET) 890 address->v4 = parse.addr.s_addr; 891 else if (ret == AF_INET6) 892 memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); 893 894 return ret; 895} 896 897static void 898nat_parse(char *arg, struct nf_conntrack *obj, int type) 899{ 900 char *colon, *error; 901 union ct_address parse; 902 903 colon = strchr(arg, ':'); 904 905 if (colon) { 906 uint16_t port; 907 908 *colon = '\0'; 909 910 port = (uint16_t)atoi(colon+1); 911 if (port == 0) { 912 if (strlen(colon+1) == 0) { 913 exit_error(PARAMETER_PROBLEM, 914 "No port specified after `:'"); 915 } else { 916 exit_error(PARAMETER_PROBLEM, 917 "Port `%s' not valid", colon+1); 918 } 919 } 920 921 error = strchr(colon+1, ':'); 922 if (error) 923 exit_error(PARAMETER_PROBLEM, 924 "Invalid port:port syntax"); 925 926 if (type == CT_OPT_SRC_NAT) 927 nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); 928 else if (type == CT_OPT_DST_NAT) 929 nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); 930 else if (type == CT_OPT_ANY_NAT) { 931 nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); 932 nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); 933 } 934 } 935 936 if (parse_addr(arg, &parse) == AF_UNSPEC) { 937 if (strlen(arg) == 0) { 938 exit_error(PARAMETER_PROBLEM, "No IP specified"); 939 } else { 940 exit_error(PARAMETER_PROBLEM, 941 "Invalid IP address `%s'", arg); 942 } 943 } 944 945 if (type == CT_OPT_SRC_NAT || type == CT_OPT_ANY_NAT) 946 nfct_set_attr_u32(tmpl.ct, ATTR_SNAT_IPV4, parse.v4); 947 else if (type == CT_OPT_DST_NAT || type == CT_OPT_ANY_NAT) 948 nfct_set_attr_u32(tmpl.ct, ATTR_DNAT_IPV4, parse.v4); 949} 950 951static void 952usage(char *prog) 953{ 954 fprintf(stdout, "Command line interface for the connection " 955 "tracking system. Version %s\n", VERSION); 956 fprintf(stdout, "Usage: %s [commands] [options]\n", prog); 957 958 fprintf(stdout, "\n%s", usage_commands); 959 fprintf(stdout, "\n%s", usage_tables); 960 fprintf(stdout, "\n%s", usage_conntrack_parameters); 961 fprintf(stdout, "\n%s", usage_expectation_parameters); 962 fprintf(stdout, "\n%s\n", usage_parameters); 963} 964 965static unsigned int output_mask; 966 967 968static int 969filter_mark(const struct nf_conntrack *ct) 970{ 971 if ((options & CT_OPT_MARK) && 972 !mark_cmp(&tmpl.mark, ct)) 973 return 1; 974 return 0; 975} 976 977 978static int 979filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) 980{ 981 int check_srcnat = options & CT_OPT_SRC_NAT ? 1 : 0; 982 int check_dstnat = options & CT_OPT_DST_NAT ? 1 : 0; 983 int has_srcnat = 0, has_dstnat = 0; 984 uint32_t ip; 985 uint16_t port; 986 987 if (options & CT_OPT_ANY_NAT) 988 check_srcnat = check_dstnat = 1; 989 990 if (check_srcnat) { 991 int check_address = 0, check_port = 0; 992 993 if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { 994 check_address = 1; 995 ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); 996 if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && 997 ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) 998 has_srcnat = 1; 999 } 1000 if (nfct_attr_is_set(obj, ATTR_SNAT_PORT)) { 1001 int ret = 0; 1002 1003 check_port = 1; 1004 port = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); 1005 if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT) && 1006 port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) 1007 ret = 1; 1008 1009 /* the address matches but the port does not. */ 1010 if (check_address && has_srcnat && !ret) 1011 has_srcnat = 0; 1012 if (!check_address && ret) 1013 has_srcnat = 1; 1014 } 1015 if (!check_address && !check_port && 1016 (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) || 1017 nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT))) 1018 has_srcnat = 1; 1019 } 1020 if (check_dstnat) { 1021 int check_address = 0, check_port = 0; 1022 1023 if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { 1024 check_address = 1; 1025 ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); 1026 if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && 1027 ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) 1028 has_dstnat = 1; 1029 } 1030 if (nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { 1031 int ret = 0; 1032 1033 check_port = 1; 1034 port = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); 1035 if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT) && 1036 port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) 1037 ret = 1; 1038 1039 /* the address matches but the port does not. */ 1040 if (check_address && has_dstnat && !ret) 1041 has_dstnat = 0; 1042 if (!check_address && ret) 1043 has_dstnat = 1; 1044 } 1045 if (!check_address && !check_port && 1046 (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) || 1047 nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT))) 1048 has_dstnat = 1; 1049 } 1050 if (options & CT_OPT_ANY_NAT) 1051 return !(has_srcnat || has_dstnat); 1052 else if ((options & CT_OPT_SRC_NAT) && (options & CT_OPT_DST_NAT)) 1053 return !(has_srcnat && has_dstnat); 1054 else if (options & CT_OPT_SRC_NAT) 1055 return !has_srcnat; 1056 else if (options & CT_OPT_DST_NAT) 1057 return !has_dstnat; 1058 1059 return 0; 1060} 1061 1062static int counter; 1063static int dump_xml_header_done = 1; 1064 1065static void __attribute__((noreturn)) 1066event_sighandler(int s) 1067{ 1068 if (dump_xml_header_done == 0) { 1069 printf("</conntrack>\n"); 1070 fflush(stdout); 1071 } 1072 1073 fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION); 1074 fprintf(stderr, "%d flow events have been shown.\n", counter); 1075 nfct_close(cth); 1076 exit(0); 1077} 1078 1079static void __attribute__((noreturn)) 1080exp_event_sighandler(int s) 1081{ 1082 if (dump_xml_header_done == 0) { 1083 printf("</expect>\n"); 1084 fflush(stdout); 1085 } 1086 1087 fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION); 1088 fprintf(stderr, "%d expectation events have been shown.\n", counter); 1089 nfct_close(cth); 1090 exit(0); 1091} 1092 1093static int event_cb(enum nf_conntrack_msg_type type, 1094 struct nf_conntrack *ct, 1095 void *data) 1096{ 1097 char buf[1024]; 1098 struct nf_conntrack *obj = data; 1099 unsigned int op_type = NFCT_O_DEFAULT; 1100 unsigned int op_flags = 0; 1101 1102 if (filter_nat(obj, ct)) 1103 return NFCT_CB_CONTINUE; 1104 1105 if (filter_mark(ct)) 1106 return NFCT_CB_CONTINUE; 1107 1108 if (options & CT_COMPARISON && 1109 !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) 1110 return NFCT_CB_CONTINUE; 1111 1112 if (output_mask & _O_XML) { 1113 op_type = NFCT_O_XML; 1114 if (dump_xml_header_done) { 1115 dump_xml_header_done = 0; 1116 printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" 1117 "<conntrack>\n"); 1118 } 1119 } 1120 if (output_mask & _O_EXT) 1121 op_flags = NFCT_OF_SHOW_LAYER3; 1122 if (output_mask & _O_TMS) { 1123 if (!(output_mask & _O_XML)) { 1124 struct timeval tv; 1125 gettimeofday(&tv, NULL); 1126 printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); 1127 } else 1128 op_flags |= NFCT_OF_TIME; 1129 } 1130 if (output_mask & _O_KTMS) 1131 op_flags |= NFCT_OF_TIMESTAMP; 1132 if (output_mask & _O_ID) 1133 op_flags |= NFCT_OF_ID; 1134 1135 nfct_snprintf(buf, sizeof(buf), ct, type, op_type, op_flags); 1136 1137 printf("%s\n", buf); 1138 fflush(stdout); 1139 1140 counter++; 1141 1142 return NFCT_CB_CONTINUE; 1143} 1144 1145static int dump_cb(enum nf_conntrack_msg_type type, 1146 struct nf_conntrack *ct, 1147 void *data) 1148{ 1149 char buf[1024]; 1150 struct nf_conntrack *obj = data; 1151 unsigned int op_type = NFCT_O_DEFAULT; 1152 unsigned int op_flags = 0; 1153 1154 if (filter_nat(obj, ct)) 1155 return NFCT_CB_CONTINUE; 1156 1157 if (filter_mark(ct)) 1158 return NFCT_CB_CONTINUE; 1159 1160 if (options & CT_COMPARISON && 1161 !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) 1162 return NFCT_CB_CONTINUE; 1163 1164 if (output_mask & _O_XML) { 1165 op_type = NFCT_O_XML; 1166 if (dump_xml_header_done) { 1167 dump_xml_header_done = 0; 1168 printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" 1169 "<conntrack>\n"); 1170 } 1171 } 1172 if (output_mask & _O_EXT) 1173 op_flags = NFCT_OF_SHOW_LAYER3; 1174 if (output_mask & _O_KTMS) 1175 op_flags |= NFCT_OF_TIMESTAMP; 1176 if (output_mask & _O_ID) 1177 op_flags |= NFCT_OF_ID; 1178 1179 nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); 1180 printf("%s\n", buf); 1181 1182 counter++; 1183 1184 return NFCT_CB_CONTINUE; 1185} 1186 1187static int delete_cb(enum nf_conntrack_msg_type type, 1188 struct nf_conntrack *ct, 1189 void *data) 1190{ 1191 int res; 1192 char buf[1024]; 1193 struct nf_conntrack *obj = data; 1194 unsigned int op_type = NFCT_O_DEFAULT; 1195 unsigned int op_flags = 0; 1196 1197 if (filter_nat(obj, ct)) 1198 return NFCT_CB_CONTINUE; 1199 1200 if (filter_mark(ct)) 1201 return NFCT_CB_CONTINUE; 1202 1203 if (options & CT_COMPARISON && 1204 !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) 1205 return NFCT_CB_CONTINUE; 1206 1207 res = nfct_query(ith, NFCT_Q_DESTROY, ct); 1208 if (res < 0) 1209 exit_error(OTHER_PROBLEM, 1210 "Operation failed: %s", 1211 err2str(errno, CT_DELETE)); 1212 1213 if (output_mask & _O_XML) 1214 op_type = NFCT_O_XML; 1215 if (output_mask & _O_EXT) 1216 op_flags = NFCT_OF_SHOW_LAYER3; 1217 if (output_mask & _O_ID) 1218 op_flags |= NFCT_OF_ID; 1219 1220 nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); 1221 printf("%s\n", buf); 1222 1223 counter++; 1224 1225 return NFCT_CB_CONTINUE; 1226} 1227 1228static int print_cb(enum nf_conntrack_msg_type type, 1229 struct nf_conntrack *ct, 1230 void *data) 1231{ 1232 char buf[1024]; 1233 unsigned int op_type = NFCT_O_DEFAULT; 1234 unsigned int op_flags = 0; 1235 1236 if (output_mask & _O_XML) 1237 op_type = NFCT_O_XML; 1238 if (output_mask & _O_EXT) 1239 op_flags = NFCT_OF_SHOW_LAYER3; 1240 if (output_mask & _O_ID) 1241 op_flags |= NFCT_OF_ID; 1242 1243 nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); 1244 printf("%s\n", buf); 1245 1246 return NFCT_CB_CONTINUE; 1247} 1248 1249static void copy_mark(struct nf_conntrack *tmp, 1250 const struct nf_conntrack *ct, 1251 const struct u32_mask *m) 1252{ 1253 if (options & CT_OPT_MARK) { 1254 uint32_t mark = nfct_get_attr_u32(ct, ATTR_MARK); 1255 mark = (mark & ~m->mask) ^ m->value; 1256 nfct_set_attr_u32(tmp, ATTR_MARK, mark); 1257 } 1258} 1259 1260static void copy_status(struct nf_conntrack *tmp, const struct nf_conntrack *ct) 1261{ 1262 if (options & CT_OPT_STATUS) { 1263 /* copy existing flags, we only allow setting them. */ 1264 uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); 1265 status |= nfct_get_attr_u32(tmp, ATTR_STATUS); 1266 nfct_set_attr_u32(tmp, ATTR_STATUS, status); 1267 } 1268} 1269 1270static int update_cb(enum nf_conntrack_msg_type type, 1271 struct nf_conntrack *ct, 1272 void *data) 1273{ 1274 int res; 1275 struct nf_conntrack *obj = data, *tmp; 1276 1277 if (filter_nat(obj, ct)) 1278 return NFCT_CB_CONTINUE; 1279 1280 if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) && 1281 nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID)) 1282 return NFCT_CB_CONTINUE; 1283 1284 if (options & CT_OPT_TUPLE_ORIG && !nfct_cmp(obj, ct, NFCT_CMP_ORIG)) 1285 return NFCT_CB_CONTINUE; 1286 if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL)) 1287 return NFCT_CB_CONTINUE; 1288 1289 tmp = nfct_new(); 1290 if (tmp == NULL) 1291 exit_error(OTHER_PROBLEM, "out of memory"); 1292 1293 nfct_copy(tmp, ct, NFCT_CP_ORIG); 1294 nfct_copy(tmp, obj, NFCT_CP_META); 1295 copy_mark(tmp, ct, &tmpl.mark); 1296 copy_status(tmp, ct); 1297 1298 /* do not send NFCT_Q_UPDATE if ct appears unchanged */ 1299 if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) { 1300 nfct_destroy(tmp); 1301 return NFCT_CB_CONTINUE; 1302 } 1303 1304 res = nfct_query(ith, NFCT_Q_UPDATE, tmp); 1305 if (res < 0) { 1306 nfct_destroy(tmp); 1307 exit_error(OTHER_PROBLEM, 1308 "Operation failed: %s", 1309 err2str(errno, CT_UPDATE)); 1310 } 1311 nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL); 1312 1313 res = nfct_query(ith, NFCT_Q_GET, tmp); 1314 if (res < 0) { 1315 nfct_destroy(tmp); 1316 /* the entry has vanish in middle of the update */ 1317 if (errno == ENOENT) { 1318 nfct_callback_unregister(ith); 1319 return NFCT_CB_CONTINUE; 1320 } 1321 exit_error(OTHER_PROBLEM, 1322 "Operation failed: %s", 1323 err2str(errno, CT_UPDATE)); 1324 } 1325 nfct_destroy(tmp); 1326 nfct_callback_unregister(ith); 1327 1328 counter++; 1329 1330 return NFCT_CB_CONTINUE; 1331} 1332 1333static int dump_exp_cb(enum nf_conntrack_msg_type type, 1334 struct nf_expect *exp, 1335 void *data) 1336{ 1337 char buf[1024]; 1338 unsigned int op_type = NFCT_O_DEFAULT; 1339 unsigned int op_flags = 0; 1340 1341 if (output_mask & _O_XML) { 1342 op_type = NFCT_O_XML; 1343 if (dump_xml_header_done) { 1344 dump_xml_header_done = 0; 1345 printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" 1346 "<expect>\n"); 1347 } 1348 } 1349 if (output_mask & _O_TMS) { 1350 if (!(output_mask & _O_XML)) { 1351 struct timeval tv; 1352 gettimeofday(&tv, NULL); 1353 printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); 1354 } else 1355 op_flags |= NFCT_OF_TIME; 1356 } 1357 1358 nfexp_snprintf(buf,sizeof(buf), exp, NFCT_T_UNKNOWN, op_type, op_flags); 1359 printf("%s\n", buf); 1360 counter++; 1361 1362 return NFCT_CB_CONTINUE; 1363} 1364 1365static int event_exp_cb(enum nf_conntrack_msg_type type, 1366 struct nf_expect *exp, void *data) 1367{ 1368 char buf[1024]; 1369 unsigned int op_type = NFCT_O_DEFAULT; 1370 unsigned int op_flags = 0; 1371 1372 if (output_mask & _O_XML) { 1373 op_type = NFCT_O_XML; 1374 if (dump_xml_header_done) { 1375 dump_xml_header_done = 0; 1376 printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" 1377 "<expect>\n"); 1378 } 1379 } 1380 if (output_mask & _O_TMS) { 1381 if (!(output_mask & _O_XML)) { 1382 struct timeval tv; 1383 gettimeofday(&tv, NULL); 1384 printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); 1385 } else 1386 op_flags |= NFCT_OF_TIME; 1387 } 1388 1389 nfexp_snprintf(buf,sizeof(buf), exp, type, op_type, op_flags); 1390 printf("%s\n", buf); 1391 fflush(stdout); 1392 counter++; 1393 1394 return NFCT_CB_CONTINUE; 1395} 1396 1397static int count_exp_cb(enum nf_conntrack_msg_type type, 1398 struct nf_expect *exp, 1399 void *data) 1400{ 1401 counter++; 1402 return NFCT_CB_CONTINUE; 1403} 1404 1405#ifndef CT_STATS_PROC 1406#define CT_STATS_PROC "/proc/net/stat/nf_conntrack" 1407#endif 1408 1409/* As of 2.6.29, we have 16 entries, this is enough */ 1410#ifndef CT_STATS_ENTRIES_MAX 1411#define CT_STATS_ENTRIES_MAX 64 1412#endif 1413 1414/* maximum string length currently is 13 characters */ 1415#ifndef CT_STATS_STRING_MAX 1416#define CT_STATS_STRING_MAX 64 1417#endif 1418 1419static int display_proc_conntrack_stats(void) 1420{ 1421 int ret = 0; 1422 FILE *fd; 1423 char buf[4096], *token, *nl; 1424 char output[CT_STATS_ENTRIES_MAX][CT_STATS_STRING_MAX]; 1425 unsigned int value[CT_STATS_ENTRIES_MAX], i, max; 1426 1427 fd = fopen(CT_STATS_PROC, "r"); 1428 if (fd == NULL) 1429 return -1; 1430 1431 if (fgets(buf, sizeof(buf), fd) == NULL) { 1432 ret = -1; 1433 goto out_err; 1434 } 1435 1436 /* trim off trailing \n */ 1437 nl = strchr(buf, '\n'); 1438 if (nl != NULL) 1439 *nl = '\0'; 1440 1441 token = strtok(buf, " "); 1442 for (i=0; token != NULL && i<CT_STATS_ENTRIES_MAX; i++) { 1443 strncpy(output[i], token, CT_STATS_STRING_MAX); 1444 output[i][CT_STATS_STRING_MAX-1]='\0'; 1445 token = strtok(NULL, " "); 1446 } 1447 max = i; 1448 1449 if (fgets(buf, sizeof(buf), fd) == NULL) { 1450 ret = -1; 1451 goto out_err; 1452 } 1453 1454 nl = strchr(buf, '\n'); 1455 while (nl != NULL) { 1456 *nl = '\0'; 1457 nl = strchr(buf, '\n'); 1458 } 1459 token = strtok(buf, " "); 1460 for (i=0; token != NULL && i<CT_STATS_ENTRIES_MAX; i++) { 1461 value[i] = (unsigned int) strtol(token, (char**) NULL, 16); 1462 token = strtok(NULL, " "); 1463 } 1464 1465 for (i=0; i<max; i++) 1466 printf("%-10s\t\t%-8u\n", output[i], value[i]); 1467 1468out_err: 1469 fclose(fd); 1470 return ret; 1471} 1472 1473static struct nfct_mnl_socket { 1474 struct mnl_socket *mnl; 1475 uint32_t portid; 1476} sock; 1477 1478static int nfct_mnl_socket_open(void) 1479{ 1480 sock.mnl = mnl_socket_open(NETLINK_NETFILTER); 1481 if (sock.mnl == NULL) { 1482 perror("mnl_socket_open"); 1483 return -1; 1484 } 1485 if (mnl_socket_bind(sock.mnl, 0, MNL_SOCKET_AUTOPID) < 0) { 1486 perror("mnl_socket_bind"); 1487 return -1; 1488 } 1489 sock.portid = mnl_socket_get_portid(sock.mnl); 1490 1491 return 0; 1492} 1493 1494static struct nlmsghdr * 1495nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) 1496{ 1497 struct nlmsghdr *nlh; 1498 struct nfgenmsg *nfh; 1499 1500 nlh = mnl_nlmsg_put_header(buf); 1501 nlh->nlmsg_type = (subsys << 8) | type; 1502 nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; 1503 nlh->nlmsg_seq = time(NULL); 1504 1505 nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); 1506 nfh->nfgen_family = AF_INET; 1507 nfh->version = NFNETLINK_V0; 1508 nfh->res_id = 0; 1509 1510 return nlh; 1511} 1512 1513static void nfct_mnl_socket_close(void) 1514{ 1515 mnl_socket_close(sock.mnl); 1516} 1517 1518static int 1519nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) 1520{ 1521 char buf[MNL_SOCKET_BUFFER_SIZE]; 1522 struct nlmsghdr *nlh; 1523 int res; 1524 1525 nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); 1526 1527 res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); 1528 if (res < 0) 1529 return res; 1530 1531 res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf)); 1532 while (res > 0) { 1533 res = mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, 1534 cb, NULL); 1535 if (res <= MNL_CB_STOP) 1536 break; 1537 1538 res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf)); 1539 } 1540 1541 return res; 1542} 1543 1544static int 1545nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb) 1546{ 1547 char buf[MNL_SOCKET_BUFFER_SIZE]; 1548 struct nlmsghdr *nlh; 1549 int res; 1550 1551 nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); 1552 1553 res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); 1554 if (res < 0) 1555 return res; 1556 1557 res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf)); 1558 if (res < 0) 1559 return res; 1560 1561 return mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, cb, NULL); 1562} 1563 1564static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) 1565{ 1566 const struct nlattr **tb = data; 1567 int type = mnl_attr_get_type(attr); 1568 1569 if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0) 1570 return MNL_CB_OK; 1571 1572 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { 1573 perror("mnl_attr_validate"); 1574 return MNL_CB_ERROR; 1575 } 1576 1577 tb[type] = attr; 1578 return MNL_CB_OK; 1579} 1580 1581static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data) 1582{ 1583 struct nlattr *tb[CTA_STATS_MAX+1] = {}; 1584 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); 1585 const char *attr2name[CTA_STATS_MAX+1] = { 1586 [CTA_STATS_SEARCHED] = "searched", 1587 [CTA_STATS_FOUND] = "found", 1588 [CTA_STATS_NEW] = "new", 1589 [CTA_STATS_INVALID] = "invalid", 1590 [CTA_STATS_IGNORE] = "ignore", 1591 [CTA_STATS_DELETE] = "delete", 1592 [CTA_STATS_DELETE_LIST] = "delete_list", 1593 [CTA_STATS_INSERT] = "insert", 1594 [CTA_STATS_INSERT_FAILED] = "insert_failed", 1595 [CTA_STATS_DROP] = "drop", 1596 [CTA_STATS_EARLY_DROP] = "early_drop", 1597 [CTA_STATS_ERROR] = "error", 1598 [CTA_STATS_SEARCH_RESTART] = "search_restart", 1599 }; 1600 int i; 1601 1602 mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, tb); 1603 1604 printf("cpu=%-4u\t", ntohs(nfg->res_id)); 1605 1606 for (i=0; i<CTA_STATS_MAX+1; i++) { 1607 if (tb[i]) { 1608 printf("%s=%u ", 1609 attr2name[i], ntohl(mnl_attr_get_u32(tb[i]))); 1610 } 1611 } 1612 printf("\n"); 1613 return MNL_CB_OK; 1614} 1615 1616static int nfexp_stats_attr_cb(const struct nlattr *attr, void *data) 1617{ 1618 const struct nlattr **tb = data; 1619 int type = mnl_attr_get_type(attr); 1620 1621 if (mnl_attr_type_valid(attr, CTA_STATS_EXP_MAX) < 0) 1622 return MNL_CB_OK; 1623 1624 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { 1625 perror("mnl_attr_validate"); 1626 return MNL_CB_ERROR; 1627 } 1628 1629 tb[type] = attr; 1630 return MNL_CB_OK; 1631} 1632 1633static int nfexp_stats_cb(const struct nlmsghdr *nlh, void *data) 1634{ 1635 struct nlattr *tb[CTA_STATS_EXP_MAX+1] = {}; 1636 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); 1637 const char *attr2name[CTA_STATS_EXP_MAX+1] = { 1638 [CTA_STATS_EXP_NEW] = "expect_new", 1639 [CTA_STATS_EXP_CREATE] = "expect_create", 1640 [CTA_STATS_EXP_DELETE] = "expect_delete", 1641 }; 1642 int i; 1643 1644 mnl_attr_parse(nlh, sizeof(*nfg), nfexp_stats_attr_cb, tb); 1645 1646 printf("cpu=%-4u\t", ntohs(nfg->res_id)); 1647 1648 for (i=0; i<CTA_STATS_EXP_MAX+1; i++) { 1649 if (tb[i]) { 1650 printf("%s=%u ", 1651 attr2name[i], ntohl(mnl_attr_get_u32(tb[i]))); 1652 } 1653 } 1654 printf("\n"); 1655 return MNL_CB_OK; 1656} 1657 1658static int nfct_stats_global_attr_cb(const struct nlattr *attr, void *data) 1659{ 1660 const struct nlattr **tb = data; 1661 int type = mnl_attr_get_type(attr); 1662 1663 if (mnl_attr_type_valid(attr, CTA_STATS_GLOBAL_MAX) < 0) 1664 return MNL_CB_OK; 1665 1666 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { 1667 perror("mnl_attr_validate"); 1668 return MNL_CB_ERROR; 1669 } 1670 1671 tb[type] = attr; 1672 return MNL_CB_OK; 1673} 1674 1675static int nfct_global_stats_cb(const struct nlmsghdr *nlh, void *data) 1676{ 1677 struct nlattr *tb[CTA_STATS_GLOBAL_MAX+1] = {}; 1678 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); 1679 1680 mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_global_attr_cb, tb); 1681 1682 if (tb[CTA_STATS_GLOBAL_ENTRIES]) { 1683 printf("%d\n", 1684 ntohl(mnl_attr_get_u32(tb[CTA_STATS_GLOBAL_ENTRIES]))); 1685 } 1686 return MNL_CB_OK; 1687} 1688 1689static struct ctproto_handler *h; 1690 1691int main(int argc, char *argv[]) 1692{ 1693 int c, cmd; 1694 unsigned int type = 0, event_mask = 0, l4flags = 0, status = 0; 1695 int res = 0, partial; 1696 size_t socketbuffersize = 0; 1697 int family = AF_UNSPEC; 1698 int l3protonum, protonum = 0; 1699 union ct_address ad; 1700 unsigned int command = 0; 1701 1702 /* we release these objects in the exit_error() path. */ 1703 if (!alloc_tmpl_objects()) 1704 exit_error(OTHER_PROBLEM, "out of memory"); 1705 1706 register_tcp(); 1707 register_udp(); 1708 register_udplite(); 1709 register_sctp(); 1710 register_dccp(); 1711 register_icmp(); 1712 register_icmpv6(); 1713 register_gre(); 1714 register_unknown(); 1715 1716 /* disable explicit missing arguments error output from getopt_long */ 1717 opterr = 0; 1718 1719 while ((c = getopt_long(argc, argv, getopt_str, opts, NULL)) != -1) { 1720 switch(c) { 1721 /* commands */ 1722 case 'L': 1723 case 'I': 1724 case 'D': 1725 case 'G': 1726 case 'F': 1727 case 'E': 1728 case 'V': 1729 case 'h': 1730 case 'C': 1731 case 'S': 1732 type = check_type(argc, argv); 1733 add_command(&command, cmd2type[c][type]); 1734 break; 1735 case 'U': 1736 type = check_type(argc, argv); 1737 if (type == 0) 1738 add_command(&command, CT_UPDATE); 1739 else 1740 exit_error(PARAMETER_PROBLEM, 1741 "Can't update expectations"); 1742 break; 1743 /* options */ 1744 case 's': 1745 case 'd': 1746 case 'r': 1747 case 'q': 1748 options |= opt2type[c]; 1749 1750 l3protonum = parse_addr(optarg, &ad); 1751 if (l3protonum == AF_UNSPEC) { 1752 exit_error(PARAMETER_PROBLEM, 1753 "Invalid IP address `%s'", optarg); 1754 } 1755 set_family(&family, l3protonum); 1756 if (l3protonum == AF_INET) { 1757 nfct_set_attr_u32(tmpl.ct, 1758 opt2family_attr[c][0], 1759 ad.v4); 1760 } else if (l3protonum == AF_INET6) { 1761 nfct_set_attr(tmpl.ct, 1762 opt2family_attr[c][1], 1763 &ad.v6); 1764 } 1765 nfct_set_attr_u8(tmpl.ct, opt2attr[c], l3protonum); 1766 break; 1767 case '{': 1768 case '}': 1769 case '[': 1770 case ']': 1771 options |= opt2type[c]; 1772 l3protonum = parse_addr(optarg, &ad); 1773 if (l3protonum == AF_UNSPEC) { 1774 exit_error(PARAMETER_PROBLEM, 1775 "Invalid IP address `%s'", optarg); 1776 } 1777 set_family(&family, l3protonum); 1778 if (l3protonum == AF_INET) { 1779 nfct_set_attr_u32(tmpl.mask, 1780 opt2family_attr[c][0], 1781 ad.v4); 1782 } else if (l3protonum == AF_INET6) { 1783 nfct_set_attr(tmpl.mask, 1784 opt2family_attr[c][1], 1785 &ad.v6); 1786 } 1787 nfct_set_attr_u8(tmpl.mask, 1788 ATTR_ORIG_L3PROTO, l3protonum); 1789 break; 1790 case 'p': 1791 options |= CT_OPT_PROTO; 1792 h = findproto(optarg, &protonum); 1793 if (!h) 1794 exit_error(PARAMETER_PROBLEM, 1795 "`%s' unsupported protocol", 1796 optarg); 1797 1798 opts = merge_options(opts, h->opts, &h->option_offset); 1799 if (opts == NULL) 1800 exit_error(OTHER_PROBLEM, "out of memory"); 1801 1802 nfct_set_attr_u8(tmpl.ct, ATTR_L4PROTO, protonum); 1803 break; 1804 case 't': 1805 options |= CT_OPT_TIMEOUT; 1806 nfct_set_attr_u32(tmpl.ct, ATTR_TIMEOUT, atol(optarg)); 1807 nfexp_set_attr_u32(tmpl.exp, 1808 ATTR_EXP_TIMEOUT, atol(optarg)); 1809 break; 1810 case 'u': 1811 options |= CT_OPT_STATUS; 1812 parse_parameter(optarg, &status, PARSE_STATUS); 1813 nfct_set_attr_u32(tmpl.ct, ATTR_STATUS, status); 1814 break; 1815 case 'e': 1816 options |= CT_OPT_EVENT_MASK; 1817 parse_parameter(optarg, &event_mask, PARSE_EVENT); 1818 break; 1819 case 'o': 1820 options |= CT_OPT_OUTPUT; 1821 parse_parameter(optarg, &output_mask, PARSE_OUTPUT); 1822 break; 1823 case 'z': 1824 options |= CT_OPT_ZERO; 1825 break; 1826 case 'n': 1827 case 'g': 1828 case 'j': { 1829 char *tmp = NULL; 1830 1831 options |= opt2type[c]; 1832 1833 if (optarg) 1834 continue; 1835 else if (optind < argc && argv[optind][0] != '-' 1836 && argv[optind][0] != '!') 1837 tmp = argv[optind++]; 1838 1839 if (tmp == NULL) 1840 continue; 1841 1842 set_family(&family, AF_INET); 1843 nat_parse(tmp, tmpl.ct, opt2type[c]); 1844 break; 1845 } 1846 case 'w': 1847 options |= opt2type[c]; 1848 nfct_set_attr_u16(tmpl.ct, 1849 opt2attr[c], 1850 strtoul(optarg, NULL, 0)); 1851 break; 1852 case 'i': 1853 case 'c': 1854 options |= opt2type[c]; 1855 nfct_set_attr_u32(tmpl.ct, 1856 opt2attr[c], 1857 strtoul(optarg, NULL, 0)); 1858 break; 1859 case 'm': 1860 options |= opt2type[c]; 1861 parse_u32_mask(optarg, &tmpl.mark); 1862 tmpl.filter_mark_kernel.val = tmpl.mark.value; 1863 tmpl.filter_mark_kernel.mask = tmpl.mark.mask; 1864 break; 1865 case 'a': 1866 fprintf(stderr, "WARNING: ignoring -%c, " 1867 "deprecated option.\n", c); 1868 break; 1869 case 'f': 1870 options |= CT_OPT_FAMILY; 1871 if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) 1872 set_family(&family, AF_INET); 1873 else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) 1874 set_family(&family, AF_INET6); 1875 else 1876 exit_error(PARAMETER_PROBLEM, 1877 "`%s' unsupported protocol", 1878 optarg); 1879 break; 1880 case 'b': 1881 socketbuffersize = atol(optarg); 1882 options |= CT_OPT_BUFFERSIZE; 1883 break; 1884 case '?': 1885 if (optopt) 1886 exit_error(PARAMETER_PROBLEM, 1887 "option `%s' requires an " 1888 "argument", argv[optind-1]); 1889 else 1890 exit_error(PARAMETER_PROBLEM, 1891 "unknown option `%s'", 1892 argv[optind-1]); 1893 break; 1894 default: 1895 if (h && h->parse_opts 1896 &&!h->parse_opts(c - h->option_offset, tmpl.ct, 1897 tmpl.exptuple, tmpl.mask, 1898 &l4flags)) 1899 exit_error(PARAMETER_PROBLEM, "parse error"); 1900 break; 1901 } 1902 } 1903 1904 /* default family */ 1905 if (family == AF_UNSPEC) 1906 family = AF_INET; 1907 1908 /* we cannot check this combination with generic_opt_check. */ 1909 if (options & CT_OPT_ANY_NAT && 1910 ((options & CT_OPT_SRC_NAT) || (options & CT_OPT_DST_NAT))) { 1911 exit_error(PARAMETER_PROBLEM, "cannot specify `--src-nat' or " 1912 "`--dst-nat' with `--any-nat'"); 1913 } 1914 cmd = bit2cmd(command); 1915 res = generic_opt_check(options, NUMBER_OF_OPT, 1916 commands_v_options[cmd], optflags, 1917 addr_valid_flags, ADDR_VALID_FLAGS_MAX, 1918 &partial); 1919 if (!res) { 1920 switch(partial) { 1921 case -1: 1922 case 0: 1923 exit_error(PARAMETER_PROBLEM, "you have to specify " 1924 "`--src' and `--dst'"); 1925 break; 1926 case 1: 1927 exit_error(PARAMETER_PROBLEM, "you have to specify " 1928 "`--reply-src' and " 1929 "`--reply-dst'"); 1930 break; 1931 } 1932 } 1933 if (!(command & CT_HELP) && h && h->final_check) 1934 h->final_check(l4flags, cmd, tmpl.ct); 1935 1936 switch(command) { 1937 struct nfct_filter_dump *filter_dump; 1938 1939 case CT_LIST: 1940 cth = nfct_open(CONNTRACK, 0); 1941 if (!cth) 1942 exit_error(OTHER_PROBLEM, "Can't open handler"); 1943 1944 if (options & CT_COMPARISON && 1945 options & CT_OPT_ZERO) 1946 exit_error(PARAMETER_PROBLEM, "Can't use -z with " 1947 "filtering parameters"); 1948 1949 nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct); 1950 1951 filter_dump = nfct_filter_dump_create(); 1952 if (filter_dump == NULL) 1953 exit_error(OTHER_PROBLEM, "OOM"); 1954 1955 nfct_filter_dump_set_attr(filter_dump, NFCT_FILTER_DUMP_MARK, 1956 &tmpl.filter_mark_kernel); 1957 nfct_filter_dump_set_attr_u8(filter_dump, 1958 NFCT_FILTER_DUMP_L3NUM, 1959 family); 1960 1961 if (options & CT_OPT_ZERO) 1962 res = nfct_query(cth, NFCT_Q_DUMP_FILTER_RESET, 1963 filter_dump); 1964 else 1965 res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump); 1966 1967 nfct_filter_dump_destroy(filter_dump); 1968 1969 if (dump_xml_header_done == 0) { 1970 printf("</conntrack>\n"); 1971 fflush(stdout); 1972 } 1973 1974 nfct_close(cth); 1975 break; 1976 1977 case EXP_LIST: 1978 cth = nfct_open(EXPECT, 0); 1979 if (!cth) 1980 exit_error(OTHER_PROBLEM, "Can't open handler"); 1981 1982 nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); 1983 res = nfexp_query(cth, NFCT_Q_DUMP, &family); 1984 nfct_close(cth); 1985 1986 if (dump_xml_header_done == 0) { 1987 printf("</expect>\n"); 1988 fflush(stdout); 1989 } 1990 break; 1991 1992 case CT_CREATE: 1993 if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) 1994 nfct_setobjopt(tmpl.ct, NFCT_SOPT_SETUP_REPLY); 1995 else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) 1996 nfct_setobjopt(tmpl.ct, NFCT_SOPT_SETUP_ORIGINAL); 1997 1998 if (options & CT_OPT_MARK) 1999 nfct_set_attr_u32(tmpl.ct, ATTR_MARK, tmpl.mark.value); 2000 2001 cth = nfct_open(CONNTRACK, 0); 2002 if (!cth) 2003 exit_error(OTHER_PROBLEM, "Can't open handler"); 2004 2005 res = nfct_query(cth, NFCT_Q_CREATE, tmpl.ct); 2006 if (res != -1) 2007 counter++; 2008 nfct_close(cth); 2009 break; 2010 2011 case EXP_CREATE: 2012 nfexp_set_attr(tmpl.exp, ATTR_EXP_MASTER, tmpl.ct); 2013 nfexp_set_attr(tmpl.exp, ATTR_EXP_EXPECTED, tmpl.exptuple); 2014 nfexp_set_attr(tmpl.exp, ATTR_EXP_MASK, tmpl.mask); 2015 2016 cth = nfct_open(EXPECT, 0); 2017 if (!cth) 2018 exit_error(OTHER_PROBLEM, "Can't open handler"); 2019 2020 res = nfexp_query(cth, NFCT_Q_CREATE, tmpl.exp); 2021 nfct_close(cth); 2022 break; 2023 2024 case CT_UPDATE: 2025 cth = nfct_open(CONNTRACK, 0); 2026 /* internal handler for delete_cb, otherwise we hit EILSEQ */ 2027 ith = nfct_open(CONNTRACK, 0); 2028 if (!cth || !ith) 2029 exit_error(OTHER_PROBLEM, "Can't open handler"); 2030 2031 nfct_callback_register(cth, NFCT_T_ALL, update_cb, tmpl.ct); 2032 2033 res = nfct_query(cth, NFCT_Q_DUMP, &family); 2034 nfct_close(ith); 2035 nfct_close(cth); 2036 break; 2037 2038 case CT_DELETE: 2039 cth = nfct_open(CONNTRACK, 0); 2040 ith = nfct_open(CONNTRACK, 0); 2041 if (!cth || !ith) 2042 exit_error(OTHER_PROBLEM, "Can't open handler"); 2043 2044 nfct_callback_register(cth, NFCT_T_ALL, delete_cb, tmpl.ct); 2045 2046 filter_dump = nfct_filter_dump_create(); 2047 if (filter_dump == NULL) 2048 exit_error(OTHER_PROBLEM, "OOM"); 2049 2050 nfct_filter_dump_set_attr(filter_dump, NFCT_FILTER_DUMP_MARK, 2051 &tmpl.filter_mark_kernel); 2052 nfct_filter_dump_set_attr_u8(filter_dump, 2053 NFCT_FILTER_DUMP_L3NUM, 2054 family); 2055 2056 res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump); 2057 2058 nfct_filter_dump_destroy(filter_dump); 2059 2060 nfct_close(ith); 2061 nfct_close(cth); 2062 break; 2063 2064 case EXP_DELETE: 2065 nfexp_set_attr(tmpl.exp, ATTR_EXP_EXPECTED, tmpl.ct); 2066 2067 cth = nfct_open(EXPECT, 0); 2068 if (!cth) 2069 exit_error(OTHER_PROBLEM, "Can't open handler"); 2070 2071 res = nfexp_query(cth, NFCT_Q_DESTROY, tmpl.exp); 2072 nfct_close(cth); 2073 break; 2074 2075 case CT_GET: 2076 cth = nfct_open(CONNTRACK, 0); 2077 if (!cth) 2078 exit_error(OTHER_PROBLEM, "Can't open handler"); 2079 2080 nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct); 2081 res = nfct_query(cth, NFCT_Q_GET, tmpl.ct); 2082 nfct_close(cth); 2083 break; 2084 2085 case EXP_GET: 2086 nfexp_set_attr(tmpl.exp, ATTR_EXP_MASTER, tmpl.ct); 2087 2088 cth = nfct_open(EXPECT, 0); 2089 if (!cth) 2090 exit_error(OTHER_PROBLEM, "Can't open handler"); 2091 2092 nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); 2093 res = nfexp_query(cth, NFCT_Q_GET, tmpl.exp); 2094 nfct_close(cth); 2095 break; 2096 2097 case CT_FLUSH: 2098 cth = nfct_open(CONNTRACK, 0); 2099 if (!cth) 2100 exit_error(OTHER_PROBLEM, "Can't open handler"); 2101 res = nfct_query(cth, NFCT_Q_FLUSH, &family); 2102 nfct_close(cth); 2103 fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); 2104 fprintf(stderr,"connection tracking table has been emptied.\n"); 2105 break; 2106 2107 case EXP_FLUSH: 2108 cth = nfct_open(EXPECT, 0); 2109 if (!cth) 2110 exit_error(OTHER_PROBLEM, "Can't open handler"); 2111 res = nfexp_query(cth, NFCT_Q_FLUSH, &family); 2112 nfct_close(cth); 2113 fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); 2114 fprintf(stderr,"expectation table has been emptied.\n"); 2115 break; 2116 2117 case CT_EVENT: 2118 if (options & CT_OPT_EVENT_MASK) { 2119 unsigned int nl_events = 0; 2120 2121 if (event_mask & CT_EVENT_F_NEW) 2122 nl_events |= NF_NETLINK_CONNTRACK_NEW; 2123 if (event_mask & CT_EVENT_F_UPD) 2124 nl_events |= NF_NETLINK_CONNTRACK_UPDATE; 2125 if (event_mask & CT_EVENT_F_DEL) 2126 nl_events |= NF_NETLINK_CONNTRACK_DESTROY; 2127 2128 cth = nfct_open(CONNTRACK, nl_events); 2129 } else { 2130 cth = nfct_open(CONNTRACK, 2131 NF_NETLINK_CONNTRACK_NEW | 2132 NF_NETLINK_CONNTRACK_UPDATE | 2133 NF_NETLINK_CONNTRACK_DESTROY); 2134 } 2135 2136 if (!cth) 2137 exit_error(OTHER_PROBLEM, "Can't open handler"); 2138 2139 if (options & CT_OPT_BUFFERSIZE) { 2140 size_t ret; 2141 ret = nfnl_rcvbufsiz(nfct_nfnlh(cth), socketbuffersize); 2142 fprintf(stderr, "NOTICE: Netlink socket buffer size " 2143 "has been set to %zu bytes.\n", ret); 2144 } 2145 signal(SIGINT, event_sighandler); 2146 signal(SIGTERM, event_sighandler); 2147 nfct_callback_register(cth, NFCT_T_ALL, event_cb, tmpl.ct); 2148 res = nfct_catch(cth); 2149 if (res == -1) { 2150 if (errno == ENOBUFS) { 2151 fprintf(stderr, 2152 "WARNING: We have hit ENOBUFS! We " 2153 "are losing events.\nThis message " 2154 "means that the current netlink " 2155 "socket buffer size is too small.\n" 2156 "Please, check --buffer-size in " 2157 "conntrack(8) manpage.\n"); 2158 } 2159 } 2160 nfct_close(cth); 2161 break; 2162 2163 case EXP_EVENT: 2164 if (options & CT_OPT_EVENT_MASK) { 2165 unsigned int nl_events = 0; 2166 2167 if (event_mask & CT_EVENT_F_NEW) 2168 nl_events |= NF_NETLINK_CONNTRACK_EXP_NEW; 2169 if (event_mask & CT_EVENT_F_UPD) 2170 nl_events |= NF_NETLINK_CONNTRACK_EXP_UPDATE; 2171 if (event_mask & CT_EVENT_F_DEL) 2172 nl_events |= NF_NETLINK_CONNTRACK_EXP_DESTROY; 2173 2174 cth = nfct_open(CONNTRACK, nl_events); 2175 } else { 2176 cth = nfct_open(EXPECT, 2177 NF_NETLINK_CONNTRACK_EXP_NEW | 2178 NF_NETLINK_CONNTRACK_EXP_UPDATE | 2179 NF_NETLINK_CONNTRACK_EXP_DESTROY); 2180 } 2181 2182 if (!cth) 2183 exit_error(OTHER_PROBLEM, "Can't open handler"); 2184 signal(SIGINT, exp_event_sighandler); 2185 signal(SIGTERM, exp_event_sighandler); 2186 nfexp_callback_register(cth, NFCT_T_ALL, event_exp_cb, NULL); 2187 res = nfexp_catch(cth); 2188 nfct_close(cth); 2189 break; 2190 case CT_COUNT: 2191 /* If we fail with netlink, fall back to /proc to ensure 2192 * backward compatibility. 2193 */ 2194 if (nfct_mnl_socket_open() < 0) 2195 goto try_proc_count; 2196 2197 res = nfct_mnl_get(NFNL_SUBSYS_CTNETLINK, 2198 IPCTNL_MSG_CT_GET_STATS, 2199 nfct_global_stats_cb); 2200 2201 nfct_mnl_socket_close(); 2202 2203 /* don't look at /proc, we got the information via ctnetlink */ 2204 if (res >= 0) 2205 break; 2206 2207try_proc_count: 2208 { 2209#define NF_CONNTRACK_COUNT_PROC "/proc/sys/net/netfilter/nf_conntrack_count" 2210 FILE *fd; 2211 int count; 2212 fd = fopen(NF_CONNTRACK_COUNT_PROC, "r"); 2213 if (fd == NULL) { 2214 exit_error(OTHER_PROBLEM, "Can't open %s", 2215 NF_CONNTRACK_COUNT_PROC); 2216 } 2217 if (fscanf(fd, "%d", &count) != 1) { 2218 exit_error(OTHER_PROBLEM, "Can't read %s", 2219 NF_CONNTRACK_COUNT_PROC); 2220 } 2221 fclose(fd); 2222 printf("%d\n", count); 2223 break; 2224 } 2225 case EXP_COUNT: 2226 cth = nfct_open(EXPECT, 0); 2227 if (!cth) 2228 exit_error(OTHER_PROBLEM, "Can't open handler"); 2229 2230 nfexp_callback_register(cth, NFCT_T_ALL, count_exp_cb, NULL); 2231 res = nfexp_query(cth, NFCT_Q_DUMP, &family); 2232 nfct_close(cth); 2233 printf("%d\n", counter); 2234 break; 2235 case CT_STATS: 2236 /* If we fail with netlink, fall back to /proc to ensure 2237 * backward compatibility. 2238 */ 2239 if (nfct_mnl_socket_open() < 0) 2240 goto try_proc; 2241 2242 res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, 2243 IPCTNL_MSG_CT_GET_STATS_CPU, 2244 nfct_stats_cb); 2245 2246 nfct_mnl_socket_close(); 2247 2248 /* don't look at /proc, we got the information via ctnetlink */ 2249 if (res >= 0) 2250 break; 2251 2252 goto try_proc; 2253 2254 case EXP_STATS: 2255 /* If we fail with netlink, fall back to /proc to ensure 2256 * backward compatibility. 2257 */ 2258 if (nfct_mnl_socket_open() < 0) 2259 goto try_proc; 2260 2261 res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP, 2262 IPCTNL_MSG_EXP_GET_STATS_CPU, 2263 nfexp_stats_cb); 2264 2265 nfct_mnl_socket_close(); 2266 2267 /* don't look at /proc, we got the information via ctnetlink */ 2268 if (res >= 0) 2269 break; 2270try_proc: 2271 if (display_proc_conntrack_stats() < 0) 2272 exit_error(OTHER_PROBLEM, "Can't open /proc interface"); 2273 break; 2274 case CT_VERSION: 2275 printf("%s v%s (conntrack-tools)\n", PROGNAME, VERSION); 2276 break; 2277 case CT_HELP: 2278 usage(argv[0]); 2279 if (options & CT_OPT_PROTO) 2280 extension_help(h, protonum); 2281 break; 2282 default: 2283 usage(argv[0]); 2284 break; 2285 } 2286 2287 if (res < 0) 2288 exit_error(OTHER_PROBLEM, "Operation failed: %s", 2289 err2str(errno, command)); 2290 2291 free_tmpl_objects(); 2292 free_options(); 2293 2294 if (command && exit_msg[cmd][0]) { 2295 fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); 2296 fprintf(stderr, exit_msg[cmd], counter); 2297 if (counter == 0 && !(command & (CT_LIST | EXP_LIST))) 2298 return EXIT_FAILURE; 2299 } 2300 2301 return EXIT_SUCCESS; 2302} 2303