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 (at) 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 26 static void 27 explain(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 36 static void 37 usage(void) 38 { 39 explain(); 40 exit(-1); 41 } 42 43 static int 44 parse_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 80 bad_val: 81 return -1; 82 } 83 84 static int 85 parse_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 memset(&sel, 0, sizeof(sel)); 95 96 while (argc > 0) { 97 if (matches(*argv, "nat") == 0) { 98 NEXT_ARG(); 99 if (parse_nat_args(&argc, &argv, &sel)) { 100 fprintf(stderr, "Illegal nat construct (%s) \n", 101 *argv); 102 explain(); 103 return -1; 104 } 105 ok++; 106 continue; 107 } else if (matches(*argv, "help") == 0) { 108 usage(); 109 } else { 110 break; 111 } 112 113 } 114 115 if (!ok) { 116 explain(); 117 return -1; 118 } 119 120 if (argc) { 121 if (matches(*argv, "reclassify") == 0) { 122 sel.action = TC_ACT_RECLASSIFY; 123 argc--; 124 argv++; 125 } else if (matches(*argv, "pipe") == 0) { 126 sel.action = TC_ACT_PIPE; 127 argc--; 128 argv++; 129 } else if (matches(*argv, "drop") == 0 || 130 matches(*argv, "shot") == 0) { 131 sel.action = TC_ACT_SHOT; 132 argc--; 133 argv++; 134 } else if (matches(*argv, "continue") == 0) { 135 sel.action = TC_ACT_UNSPEC; 136 argc--; 137 argv++; 138 } else if (matches(*argv, "pass") == 0) { 139 sel.action = TC_ACT_OK; 140 argc--; 141 argv++; 142 } 143 } 144 145 if (argc) { 146 if (matches(*argv, "index") == 0) { 147 NEXT_ARG(); 148 if (get_u32(&sel.index, *argv, 10)) { 149 fprintf(stderr, "Pedit: Illegal \"index\"\n"); 150 return -1; 151 } 152 argc--; 153 argv++; 154 } 155 } 156 157 tail = NLMSG_TAIL(n); 158 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 159 addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel)); 160 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 161 162 *argc_p = argc; 163 *argv_p = argv; 164 return 0; 165 } 166 167 static int 168 print_nat(struct action_util *au,FILE * f, struct rtattr *arg) 169 { 170 struct tc_nat *sel; 171 struct rtattr *tb[TCA_NAT_MAX + 1]; 172 char buf1[256]; 173 char buf2[256]; 174 SPRINT_BUF(buf3); 175 int len; 176 177 if (arg == NULL) 178 return -1; 179 180 parse_rtattr_nested(tb, TCA_NAT_MAX, arg); 181 182 if (tb[TCA_NAT_PARMS] == NULL) { 183 fprintf(f, "[NULL nat parameters]"); 184 return -1; 185 } 186 sel = RTA_DATA(tb[TCA_NAT_PARMS]); 187 188 len = ffs(sel->mask); 189 len = len ? 33 - len : 0; 190 191 fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ? 192 "egress" : "ingress", 193 format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), 194 len, 195 format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)), 196 action_n2a(sel->action, buf3, sizeof (buf3))); 197 198 if (show_stats) { 199 if (tb[TCA_NAT_TM]) { 200 struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]); 201 print_tm(f,tm); 202 } 203 } 204 205 return 0; 206 } 207 208 struct action_util nat_action_util = { 209 .id = "nat", 210 .parse_aopt = parse_nat, 211 .print_aopt = print_nat, 212 }; 213