conntrack flush module
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
6.3KB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. #include <linux/types.h>
  7. #include <sys/ioctl.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <arpa/inet.h>
  11. #include <getopt.h>
  12. #include <netdb.h>
  13. #include "ct_flush.h"
  14. /* name of device (major 10, minor 243) */
  15. #define CT_FLUSH_DEVICE "/dev/ct_flush"
  16. /* default pattern: match no IP, all ports */
  17. #define PATTERN_INIT { {0, 0, 0, 0xffff}, {0, 0, 0, 0xffff}, 0, 0 }
  18. int exec_flush(struct search_pattern *hostpat) {
  19. struct search_pattern pat;
  20. int dev, ret = 0;
  21. if ((dev = open(CT_FLUSH_DEVICE, O_RDWR)) == -1 ) {
  22. perror("open");
  23. return -1;
  24. }
  25. pat.count = 0;
  26. pat.proto = hostpat->proto;
  27. pat.src.ip = htonl(hostpat->src.ip);
  28. pat.src.mask = htonl(hostpat->src.mask);
  29. pat.src.portlo = htons(hostpat->src.portlo);
  30. pat.src.porthi = htons(hostpat->src.porthi);
  31. pat.dst.ip = htonl(hostpat->dst.ip);
  32. pat.dst.mask = htonl(hostpat->dst.mask);
  33. pat.dst.portlo = htons(hostpat->dst.portlo);
  34. pat.dst.porthi = htons(hostpat->dst.porthi);
  35. if ((ret = ioctl(dev, IOCTL_CT_FLUSH, &pat)) == -1)
  36. perror ("ioctl");
  37. hostpat->count = pat.count;
  38. close(dev);
  39. return ret;
  40. }
  41. int parse_proto(char *arg, u_int8_t *val) {
  42. struct protoent *p;
  43. p = getprotobyname(arg);
  44. if (p != NULL) {
  45. *val = (u_int8_t)(p->p_proto);
  46. } else if (!strcmp(arg, "all")) {
  47. *val = 0;
  48. } else {
  49. long num = strtol(arg, NULL, 0);
  50. if (num <= 0 || num > 255)
  51. return 1;
  52. *val = (u_int8_t)num;
  53. }
  54. return 0;
  55. }
  56. void print_proto(char *pre, u_int8_t val) {
  57. struct protoent *p;
  58. if (val) {
  59. if ((p = getprotobynumber(val))) {
  60. printf("%s%s ", pre, p->p_name);
  61. } else {
  62. printf("%s%d ", pre, p->p_proto);
  63. }
  64. }
  65. }
  66. int parse_ipmask(char *arg, u_int32_t *ip, u_int32_t *mask) {
  67. struct in_addr tmp;
  68. char *p;
  69. /* netmask */
  70. if ((p = strchr(arg, '/')) != NULL) {
  71. if (inet_pton(AF_INET, p+1, &tmp) > 0) {
  72. *mask = (u_int32_t)(tmp.s_addr);
  73. } else {
  74. long num = strtol(p+1, NULL, 0);
  75. if (num <= 0 || num > 32)
  76. return 1;
  77. *mask = (u_int32_t) htonl(0xFFFFFFFF<<(32-num));
  78. }
  79. *p = 0;
  80. } else {
  81. *mask = 0xFFFFFFFF;
  82. }
  83. /* ip address */
  84. if (inet_pton(AF_INET, arg, &tmp) <= 0)
  85. return 1;
  86. *ip = (u_int32_t)(tmp.s_addr);
  87. return 0;
  88. }
  89. void print_ipmask(char *pre, u_int32_t ip, u_int32_t mask) {
  90. if (mask != 0 && ip != 0) {
  91. int i = 32;
  92. char ip_str[INET_ADDRSTRLEN];
  93. u_int32_t bits = 0xFFFFFFFEL;
  94. u_int32_t maskaddr = ntohl(mask);
  95. inet_ntop(AF_INET, &ip, ip_str, sizeof(ip_str));
  96. while (--i >= 0 && maskaddr != bits)
  97. bits <<= 1;
  98. if (bits == 0) {
  99. printf("%s%s ", pre, ip_str);
  100. } else if (i >= 0) {
  101. printf("%s%s/%d ", pre, ip_str, i);
  102. } else {
  103. char mask_str[INET_ADDRSTRLEN];
  104. inet_ntop(AF_INET, &mask, mask_str, sizeof(ip_str));
  105. printf("%s%s/%s ", pre, ip_str, mask_str);
  106. }
  107. }
  108. }
  109. int parse_portrange(char *arg, u_int16_t *portlo, u_int16_t *porthi) {
  110. long num;
  111. char *p;
  112. /* check for portrange */
  113. if ((p = strchr(arg, ':')) != NULL || (p = strchr(arg, '-')) != NULL) {
  114. /* try parse port */
  115. num = strtol(p+1, NULL, 0);
  116. if (num < 0 || num > 65535)
  117. return 1;
  118. *porthi = (u_int16_t)num;
  119. *p = 0;
  120. }
  121. /* try parse port */
  122. num = strtol(arg, NULL, 0);
  123. if (num < 0 || num > 65535)
  124. return 1;
  125. *portlo = (u_int16_t)num;
  126. if (p == NULL)
  127. *porthi = *portlo;
  128. if (portlo > porthi)
  129. return 1;
  130. return 0;
  131. }
  132. void print_portrange(char *pre, u_int16_t portlo, u_int16_t porthi) {
  133. if (portlo == porthi)
  134. printf("%s%d ", pre, portlo);
  135. else if (portlo != 0 || porthi != 65535)
  136. printf("%s%d:%d ", pre, portlo, porthi);
  137. }
  138. static struct option opts[] = {
  139. {"protocol", 1, 0, 'p'},
  140. {"source", 1, 0, 's'},
  141. {"src", 1, 0, 's'},
  142. {"sport", 1, 0, 'a'},
  143. {"destination", 1, 0, 'd'},
  144. {"dst", 1, 0, 'd'},
  145. {"dport", 1, 0, 'b'},
  146. {"help", 0, 0, 'h'},
  147. {"verbose", 0, 0, 'v'},
  148. {0, 0, 0, 0}
  149. };
  150. int main(int argc, char *argv[]) {
  151. struct search_pattern pat = PATTERN_INIT;
  152. int arg = 0, code = 0, verbose = 0;
  153. if (argc == 1) {
  154. fprintf(stderr, "No argument given. try --help\n");
  155. exit(-1);
  156. }
  157. while (code != -1) {
  158. code = getopt_long(argc, argv, "p:s:d:hv", opts, &arg);
  159. switch (code) {
  160. case 'p': /* proto */
  161. if (parse_proto(optarg, &pat.proto)) {
  162. fprintf(stderr, "Error parsing value: %s\n", optarg);
  163. exit(-1);
  164. }
  165. break;
  166. case 's': /* src */
  167. if (parse_ipmask(optarg, &pat.src.ip, &pat.src.mask)) {
  168. fprintf(stderr, "Error parsing value: %s\n", optarg);
  169. exit(-1);
  170. }
  171. break;
  172. case 'a': /* sport */
  173. if (pat.proto != IPPROTO_TCP && pat.proto != IPPROTO_UDP) {
  174. fprintf(stderr, "--sport only allowed with tcp/udp protocol\n");
  175. exit(-1);
  176. }
  177. if (parse_portrange(optarg, &pat.src.portlo, &pat.src.porthi)) {
  178. fprintf(stderr, "Error parsing value: %s\n", optarg);
  179. exit(-1);
  180. }
  181. break;
  182. case 'd': /* dst */
  183. if (parse_ipmask(optarg, &pat.dst.ip, &pat.dst.mask)) {
  184. fprintf(stderr, "Error parsing value: %s\n", optarg);
  185. exit(-1);
  186. }
  187. break;
  188. case 'b': /* dport */
  189. if (pat.proto != IPPROTO_TCP && pat.proto != IPPROTO_UDP) {
  190. fprintf(stderr, "--dport only allowed with tcp/udp protocol\n");
  191. exit(-1);
  192. }
  193. if (parse_portrange(optarg, &pat.dst.portlo, &pat.dst.porthi)) {
  194. fprintf(stderr, "Error parsing value: %s\n", optarg);
  195. exit(-1);
  196. }
  197. break;
  198. case 'h': /* help */
  199. printf("Usage: ct_flush [options]\n"
  200. "Options: \n"
  201. " --protocol -p protocol ('tcp', '6')\n"
  202. " --source -s address[/mask]\n"
  203. " --destination -d address[/mask]\n"
  204. " --sport port[-port] (only with proto tcp/udp)\n"
  205. " --dport port[-port] (only with proto tcp/udp)\n"
  206. " --verbose -v be verbose\n"
  207. " --help -h this help\n"
  208. "\n");
  209. exit(0);
  210. break;
  211. case 'v': /* verbose */
  212. verbose = 1;
  213. break;
  214. case '?': /* error */
  215. exit(-1);
  216. break;
  217. default: /* unknown / all options parsed */
  218. break;
  219. }
  220. }
  221. if (verbose) {
  222. printf("flushing: ");
  223. print_proto("proto=", pat.proto);
  224. print_ipmask("src=", pat.src.ip, pat.src.mask);
  225. print_portrange("sport=", pat.src.portlo, pat.src.porthi);
  226. print_ipmask("dst=", pat.dst.ip, pat.dst.mask);
  227. print_portrange("dport=", pat.dst.portlo, pat.dst.porthi);
  228. printf("\n");
  229. }
  230. exec_flush(&pat);
  231. if (verbose)
  232. printf("%d flushed\n", pat.count);
  233. return 0;
  234. }