1/* 2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published 6 * by the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com> 10 */ 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include <sys/types.h> 16#include <dirent.h> 17#include <sys/stat.h> 18#include <fcntl.h> 19#include <unistd.h> 20#include <time.h> 21#include <netinet/in.h> 22#include <errno.h> 23 24#include <libmnl/libmnl.h> 25#include <linux/netfilter/nfnetlink_cttimeout.h> 26#include <libnetfilter_cttimeout/libnetfilter_cttimeout.h> 27 28#include "nfct.h" 29 30static void 31nfct_cmd_timeout_usage(char *argv[]) 32{ 33 fprintf(stderr, "nfct v%s: Missing command\n" 34 "%s timeout list|add|delete|get|flush " 35 "[parameters...]\n", VERSION, argv[0]); 36} 37 38int nfct_cmd_timeout_parse_params(int argc, char *argv[]) 39{ 40 int cmd = NFCT_CMD_NONE, ret; 41 42 if (argc < 3) { 43 nfct_cmd_timeout_usage(argv); 44 return -1; 45 } 46 if (strncmp(argv[2], "list", strlen(argv[2])) == 0) 47 cmd = NFCT_CMD_LIST; 48 else if (strncmp(argv[2], "add", strlen(argv[2])) == 0) 49 cmd = NFCT_CMD_ADD; 50 else if (strncmp(argv[2], "delete", strlen(argv[2])) == 0) 51 cmd = NFCT_CMD_DELETE; 52 else if (strncmp(argv[2], "get", strlen(argv[2])) == 0) 53 cmd = NFCT_CMD_GET; 54 else if (strncmp(argv[2], "flush", strlen(argv[2])) == 0) 55 cmd = NFCT_CMD_FLUSH; 56 else { 57 fprintf(stderr, "nfct v%s: Unknown command: %s\n", 58 VERSION, argv[2]); 59 nfct_cmd_timeout_usage(argv); 60 return -1; 61 } 62 switch(cmd) { 63 case NFCT_CMD_LIST: 64 ret = nfct_cmd_timeout_list(argc, argv); 65 break; 66 case NFCT_CMD_ADD: 67 ret = nfct_cmd_timeout_add(argc, argv); 68 break; 69 case NFCT_CMD_DELETE: 70 ret = nfct_cmd_timeout_delete(argc, argv); 71 break; 72 case NFCT_CMD_GET: 73 ret = nfct_cmd_timeout_get(argc, argv); 74 break; 75 case NFCT_CMD_FLUSH: 76 ret = nfct_cmd_timeout_flush(argc, argv); 77 break; 78 } 79 80 return ret; 81} 82 83static int nfct_timeout_cb(const struct nlmsghdr *nlh, void *data) 84{ 85 struct nfct_timeout *t; 86 char buf[4096]; 87 88 t = nfct_timeout_alloc(); 89 if (t == NULL) { 90 nfct_perror("OOM"); 91 goto err; 92 } 93 94 if (nfct_timeout_nlmsg_parse_payload(nlh, t) < 0) { 95 nfct_perror("nfct_timeout_nlmsg_parse_payload"); 96 goto err_free; 97 } 98 99 nfct_timeout_snprintf(buf, sizeof(buf), t, NFCT_TIMEOUT_O_DEFAULT, 0); 100 printf("%s\n", buf); 101 102err_free: 103 nfct_timeout_free(t); 104err: 105 return MNL_CB_OK; 106} 107 108int nfct_cmd_timeout_list(int argc, char *argv[]) 109{ 110 struct mnl_socket *nl; 111 char buf[MNL_SOCKET_BUFFER_SIZE]; 112 struct nlmsghdr *nlh; 113 unsigned int seq, portid; 114 int ret; 115 116 if (argc > 3) { 117 nfct_perror("too many arguments"); 118 return -1; 119 } 120 121 seq = time(NULL); 122 nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_GET, 123 NLM_F_DUMP, seq); 124 125 nl = mnl_socket_open(NETLINK_NETFILTER); 126 if (nl == NULL) { 127 nfct_perror("mnl_socket_open"); 128 return -1; 129 } 130 131 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { 132 nfct_perror("mnl_socket_bind"); 133 return -1; 134 } 135 portid = mnl_socket_get_portid(nl); 136 137 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 138 nfct_perror("mnl_socket_send"); 139 return -1; 140 } 141 142 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 143 while (ret > 0) { 144 ret = mnl_cb_run(buf, ret, seq, portid, nfct_timeout_cb, NULL); 145 if (ret <= 0) 146 break; 147 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 148 } 149 if (ret == -1) { 150 nfct_perror("error"); 151 return -1; 152 } 153 mnl_socket_close(nl); 154 155 return 0; 156} 157 158static uint32_t nfct_timeout_attr_max[IPPROTO_MAX] = { 159 [IPPROTO_ICMP] = NFCT_TIMEOUT_ATTR_ICMP_MAX, 160 [IPPROTO_TCP] = NFCT_TIMEOUT_ATTR_TCP_MAX, 161 [IPPROTO_UDP] = NFCT_TIMEOUT_ATTR_UDP_MAX, 162 [IPPROTO_UDPLITE] = NFCT_TIMEOUT_ATTR_UDPLITE_MAX, 163 [IPPROTO_SCTP] = NFCT_TIMEOUT_ATTR_SCTP_MAX, 164 [IPPROTO_DCCP] = NFCT_TIMEOUT_ATTR_DCCP_MAX, 165 [IPPROTO_ICMPV6] = NFCT_TIMEOUT_ATTR_ICMPV6_MAX, 166 [IPPROTO_GRE] = NFCT_TIMEOUT_ATTR_GRE_MAX, 167 [IPPROTO_RAW] = NFCT_TIMEOUT_ATTR_GENERIC_MAX, 168}; 169 170int nfct_cmd_timeout_add(int argc, char *argv[]) 171{ 172 struct mnl_socket *nl; 173 char buf[MNL_SOCKET_BUFFER_SIZE]; 174 struct nlmsghdr *nlh; 175 uint32_t portid, seq; 176 struct nfct_timeout *t; 177 uint16_t l3proto; 178 uint8_t l4proto; 179 int ret, i; 180 unsigned int j; 181 182 if (argc < 6) { 183 nfct_perror("missing parameters\n" 184 "syntax: nfct timeout add name " 185 "family protocol state1 " 186 "timeout1 state2 timeout2..."); 187 return -1; 188 } 189 190 t = nfct_timeout_alloc(); 191 if (t == NULL) { 192 nfct_perror("OOM"); 193 return -1; 194 } 195 196 nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); 197 198 if (strcmp(argv[4], "inet") == 0) 199 l3proto = AF_INET; 200 else if (strcmp(argv[4], "inet6") == 0) 201 l3proto = AF_INET6; 202 else { 203 nfct_perror("unknown layer 3 protocol"); 204 return -1; 205 } 206 nfct_timeout_attr_set_u16(t, NFCT_TIMEOUT_ATTR_L3PROTO, l3proto); 207 208 if (strcmp(argv[5], "tcp") == 0) 209 l4proto = IPPROTO_TCP; 210 else if (strcmp(argv[5], "udp") == 0) 211 l4proto = IPPROTO_UDP; 212 else if (strcmp(argv[5], "udplite") == 0) 213 l4proto = IPPROTO_UDPLITE; 214 else if (strcmp(argv[5], "sctp") == 0) 215 l4proto = IPPROTO_SCTP; 216 else if (strcmp(argv[5], "dccp") == 0) 217 l4proto = IPPROTO_DCCP; 218 else if (strcmp(argv[5], "icmp") == 0) 219 l4proto = IPPROTO_ICMP; 220 else if (strcmp(argv[5], "icmpv6") == 0) 221 l4proto = IPPROTO_ICMPV6; 222 else if (strcmp(argv[5], "gre") == 0) 223 l4proto = IPPROTO_GRE; 224 else if (strcmp(argv[5], "generic") == 0) 225 l4proto = IPPROTO_RAW; 226 else { 227 nfct_perror("unknown layer 4 protocol"); 228 return -1; 229 } 230 nfct_timeout_attr_set_u8(t, NFCT_TIMEOUT_ATTR_L4PROTO, l4proto); 231 232 for (i=6; i<argc; i+=2) { 233 int matching = -1; 234 235 for (j=0; j<nfct_timeout_attr_max[l4proto]; j++) { 236 const char *state_name; 237 238 state_name = 239 nfct_timeout_policy_attr_to_name(l4proto, j); 240 if (state_name == NULL) { 241 nfct_perror("state name is NULL"); 242 return -1; 243 } 244 if (strcasecmp(argv[i], state_name) != 0) 245 continue; 246 247 matching = j; 248 break; 249 } 250 if (matching != -1) { 251 if (i+1 >= argc) { 252 nfct_perror("missing value for this timeout"); 253 return -1; 254 } 255 nfct_timeout_policy_attr_set_u32(t, matching, 256 atoi(argv[i+1])); 257 matching = -1; 258 } else { 259 fprintf(stderr, "nfct v%s: Wrong state name: `%s' " 260 "for protocol `%s'\n", 261 VERSION, argv[i], argv[5]); 262 return -1; 263 } 264 } 265 266 seq = time(NULL); 267 nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_NEW, 268 NLM_F_CREATE | NLM_F_ACK, seq); 269 nfct_timeout_nlmsg_build_payload(nlh, t); 270 271 nfct_timeout_free(t); 272 273 nl = mnl_socket_open(NETLINK_NETFILTER); 274 if (nl == NULL) { 275 nfct_perror("mnl_socket_open"); 276 return -1; 277 } 278 279 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { 280 nfct_perror("mnl_socket_bind"); 281 return -1; 282 } 283 portid = mnl_socket_get_portid(nl); 284 285 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 286 nfct_perror("mnl_socket_send"); 287 return -1; 288 } 289 290 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 291 while (ret > 0) { 292 ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); 293 if (ret <= 0) 294 break; 295 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 296 } 297 if (ret == -1) { 298 nfct_perror("error"); 299 return -1; 300 } 301 mnl_socket_close(nl); 302 303 return 0; 304} 305 306int nfct_cmd_timeout_delete(int argc, char *argv[]) 307{ 308 struct mnl_socket *nl; 309 char buf[MNL_SOCKET_BUFFER_SIZE]; 310 struct nlmsghdr *nlh; 311 uint32_t portid, seq; 312 struct nfct_timeout *t; 313 int ret; 314 315 if (argc < 4) { 316 nfct_perror("missing timeout policy name"); 317 return -1; 318 } else if (argc > 4) { 319 nfct_perror("too many arguments"); 320 return -1; 321 } 322 323 t = nfct_timeout_alloc(); 324 if (t == NULL) { 325 nfct_perror("OOM"); 326 return -1; 327 } 328 329 nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); 330 331 seq = time(NULL); 332 nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DELETE, 333 NLM_F_ACK, seq); 334 nfct_timeout_nlmsg_build_payload(nlh, t); 335 336 nfct_timeout_free(t); 337 338 nl = mnl_socket_open(NETLINK_NETFILTER); 339 if (nl == NULL) { 340 nfct_perror("mnl_socket_open"); 341 return -1; 342 } 343 344 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { 345 nfct_perror("mnl_socket_bind"); 346 return -1; 347 } 348 portid = mnl_socket_get_portid(nl); 349 350 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 351 nfct_perror("mnl_socket_send"); 352 return -1; 353 } 354 355 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 356 while (ret > 0) { 357 ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); 358 if (ret <= 0) 359 break; 360 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 361 } 362 if (ret == -1) { 363 nfct_perror("error"); 364 return -1; 365 } 366 367 mnl_socket_close(nl); 368 369 return 0; 370} 371 372int nfct_cmd_timeout_get(int argc, char *argv[]) 373{ 374 struct mnl_socket *nl; 375 char buf[MNL_SOCKET_BUFFER_SIZE]; 376 struct nlmsghdr *nlh; 377 uint32_t portid, seq; 378 struct nfct_timeout *t; 379 int ret; 380 381 if (argc < 4) { 382 nfct_perror("missing timeout policy name"); 383 return -1; 384 } else if (argc > 4) { 385 nfct_perror("too many arguments"); 386 return -1; 387 } 388 389 t = nfct_timeout_alloc(); 390 if (t == NULL) { 391 nfct_perror("OOM"); 392 return -1; 393 } 394 nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); 395 396 seq = time(NULL); 397 nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_GET, 398 NLM_F_ACK, seq); 399 400 nfct_timeout_nlmsg_build_payload(nlh, t); 401 402 nfct_timeout_free(t); 403 404 nl = mnl_socket_open(NETLINK_NETFILTER); 405 if (nl == NULL) { 406 nfct_perror("mnl_socket_open"); 407 return -1; 408 } 409 410 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { 411 nfct_perror("mnl_socket_bind"); 412 return -1; 413 } 414 portid = mnl_socket_get_portid(nl); 415 416 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 417 nfct_perror("mnl_socket_send"); 418 return -1; 419 } 420 421 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 422 while (ret > 0) { 423 ret = mnl_cb_run(buf, ret, seq, portid, nfct_timeout_cb, NULL); 424 if (ret <= 0) 425 break; 426 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 427 } 428 if (ret == -1) { 429 nfct_perror("error"); 430 return -1; 431 } 432 mnl_socket_close(nl); 433 434 return 0; 435} 436 437int nfct_cmd_timeout_flush(int argc, char *argv[]) 438{ 439 struct mnl_socket *nl; 440 char buf[MNL_SOCKET_BUFFER_SIZE]; 441 struct nlmsghdr *nlh; 442 uint32_t portid, seq; 443 int ret; 444 445 if (argc > 3) { 446 nfct_perror("too many arguments"); 447 return -1; 448 } 449 450 seq = time(NULL); 451 nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DELETE, 452 NLM_F_ACK, seq); 453 454 nl = mnl_socket_open(NETLINK_NETFILTER); 455 if (nl == NULL) { 456 nfct_perror("mnl_socket_open"); 457 return -1; 458 } 459 460 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { 461 nfct_perror("mnl_socket_bind"); 462 return -1; 463 } 464 portid = mnl_socket_get_portid(nl); 465 466 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 467 nfct_perror("mnl_socket_send"); 468 return -1; 469 } 470 471 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 472 while (ret > 0) { 473 ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); 474 if (ret <= 0) 475 break; 476 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 477 } 478 if (ret == -1) { 479 nfct_perror("error"); 480 return -1; 481 } 482 483 mnl_socket_close(nl); 484 485 return 0; 486} 487