1/* 2 * m_nat.c NAT module 3 * 4 * This program is free software; you can distribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Herbert Xu <herbert@gondor.apana.org.au> 10 * 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <unistd.h> 16#include <syslog.h> 17#include <fcntl.h> 18#include <sys/socket.h> 19#include <netinet/in.h> 20#include <arpa/inet.h> 21#include <string.h> 22#include "utils.h" 23#include "tc_util.h" 24#include <linux/tc_act/tc_nat.h> 25 26static void 27explain(void) 28{ 29 fprintf(stderr, "Usage: ... nat NAT\n" 30 "NAT := DIRECTION OLD NEW\n" 31 "DIRECTION := { ingress | egress }\n" 32 "OLD := PREFIX\n" 33 "NEW := ADDRESS\n"); 34} 35 36static void 37usage(void) 38{ 39 explain(); 40 exit(-1); 41} 42 43static int 44parse_nat_args(int *argc_p, char ***argv_p, struct tc_nat *sel) 45{ 46 int argc = *argc_p; 47 char **argv = *argv_p; 48 inet_prefix addr; 49 50 if (argc <= 0) 51 return -1; 52 53 if (matches(*argv, "egress") == 0) 54 sel->flags |= TCA_NAT_FLAG_EGRESS; 55 else if (matches(*argv, "ingress") != 0) 56 goto bad_val; 57 58 NEXT_ARG(); 59 60 if (get_prefix_1(&addr, *argv, AF_INET)) 61 goto bad_val; 62 63 sel->old_addr = addr.data[0]; 64 sel->mask = htonl(~0u << (32 - addr.bitlen)); 65 66 NEXT_ARG(); 67 68 if (get_prefix_1(&addr, *argv, AF_INET)) 69 goto bad_val; 70 71 sel->new_addr = addr.data[0]; 72 73 argc--; 74 argv++; 75 76 *argc_p = argc; 77 *argv_p = argv; 78 return 0; 79 80bad_val: 81 return -1; 82} 83 84static int 85parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) 86{ 87 struct tc_nat sel = {}; 88 89 int argc = *argc_p; 90 char **argv = *argv_p; 91 int ok = 0; 92 struct rtattr *tail; 93 94 while (argc > 0) { 95 if (matches(*argv, "nat") == 0) { 96 NEXT_ARG(); 97 if (parse_nat_args(&argc, &argv, &sel)) { 98 fprintf(stderr, "Illegal nat construct (%s)\n", 99 *argv); 100 explain(); 101 return -1; 102 } 103 ok++; 104 continue; 105 } else if (matches(*argv, "help") == 0) { 106 usage(); 107 } else { 108 break; 109 } 110 111 } 112 113 if (!ok) { 114 explain(); 115 return -1; 116 } 117 118 parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK); 119 120 if (argc) { 121 if (matches(*argv, "index") == 0) { 122 NEXT_ARG(); 123 if (get_u32(&sel.index, *argv, 10)) { 124 fprintf(stderr, "Nat: Illegal \"index\"\n"); 125 return -1; 126 } 127 argc--; 128 argv++; 129 } 130 } 131 132 tail = NLMSG_TAIL(n); 133 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 134 addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel)); 135 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 136 137 *argc_p = argc; 138 *argv_p = argv; 139 return 0; 140} 141 142static int 143print_nat(struct action_util *au, FILE * f, struct rtattr *arg) 144{ 145 struct tc_nat *sel; 146 struct rtattr *tb[TCA_NAT_MAX + 1]; 147 char buf1[256]; 148 char buf2[256]; 149 150 int len; 151 152 if (arg == NULL) 153 return -1; 154 155 parse_rtattr_nested(tb, TCA_NAT_MAX, arg); 156 157 if (tb[TCA_NAT_PARMS] == NULL) { 158 fprintf(f, "[NULL nat parameters]"); 159 return -1; 160 } 161 sel = RTA_DATA(tb[TCA_NAT_PARMS]); 162 163 len = ffs(sel->mask); 164 len = len ? 33 - len : 0; 165 166 fprintf(f, " nat %s %s/%d %s", sel->flags & TCA_NAT_FLAG_EGRESS ? 167 "egress" : "ingress", 168 format_host_r(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), 169 len, 170 format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2))); 171 print_action_control(f, " ", sel->action, ""); 172 173 if (show_stats) { 174 if (tb[TCA_NAT_TM]) { 175 struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]); 176 177 print_tm(f, tm); 178 } 179 } 180 181 return 0; 182} 183 184struct action_util nat_action_util = { 185 .id = "nat", 186 .parse_aopt = parse_nat, 187 .print_aopt = print_nat, 188}; 189