iprule.c revision aba5acdfdb347d2c21fc67d613d83d4430ca3937
1/* 2 * iprule.c "ip rule". 3 * 4 * This program is free software; you can redistribute 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: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 * 11 * 12 * Changes: 13 * 14 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 15 */ 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <unistd.h> 20#include <syslog.h> 21#include <fcntl.h> 22#include <sys/socket.h> 23#include <netinet/in.h> 24#include <netinet/ip.h> 25#include <arpa/inet.h> 26#include <string.h> 27 28#include "rt_names.h" 29#include "utils.h" 30 31static void usage(void) __attribute__((noreturn)); 32 33static void usage(void) 34{ 35 fprintf(stderr, "Usage: ip rule [ list | add | del ] SELECTOR ACTION\n"); 36 fprintf(stderr, "SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]\n"); 37 fprintf(stderr, " [ dev STRING ] [ pref NUMBER ]\n"); 38 fprintf(stderr, "ACTION := [ table TABLE_ID ] [ nat ADDRESS ]\n"); 39 fprintf(stderr, " [ prohibit | reject | unreachable ]\n"); 40 fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); 41 fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n"); 42 exit(-1); 43} 44 45int print_rule(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 46{ 47 FILE *fp = (FILE*)arg; 48 struct rtmsg *r = NLMSG_DATA(n); 49 int len = n->nlmsg_len; 50 int host_len = -1; 51 struct rtattr * tb[RTA_MAX+1]; 52 char abuf[256]; 53 SPRINT_BUF(b1); 54 55 if (n->nlmsg_type != RTM_NEWRULE) 56 return 0; 57 58 len -= NLMSG_LENGTH(sizeof(*r)); 59 if (len < 0) 60 return -1; 61 62 memset(tb, 0, sizeof(tb)); 63 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 64 65 if (r->rtm_family == AF_INET) 66 host_len = 32; 67 else if (r->rtm_family == AF_INET6) 68 host_len = 128; 69 else if (r->rtm_family == AF_DECnet) 70 host_len = 16; 71 else if (r->rtm_family == AF_IPX) 72 host_len = 80; 73 74 if (tb[RTA_PRIORITY]) 75 fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[RTA_PRIORITY])); 76 else 77 fprintf(fp, "0:\t"); 78 79 if (tb[RTA_SRC]) { 80 if (r->rtm_src_len != host_len) { 81 fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, 82 RTA_PAYLOAD(tb[RTA_SRC]), 83 RTA_DATA(tb[RTA_SRC]), 84 abuf, sizeof(abuf)), 85 r->rtm_src_len 86 ); 87 } else { 88 fprintf(fp, "from %s ", format_host(r->rtm_family, 89 RTA_PAYLOAD(tb[RTA_SRC]), 90 RTA_DATA(tb[RTA_SRC]), 91 abuf, sizeof(abuf)) 92 ); 93 } 94 } else if (r->rtm_src_len) { 95 fprintf(fp, "from 0/%d ", r->rtm_src_len); 96 } else { 97 fprintf(fp, "from all "); 98 } 99 100 if (tb[RTA_DST]) { 101 if (r->rtm_dst_len != host_len) { 102 fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, 103 RTA_PAYLOAD(tb[RTA_DST]), 104 RTA_DATA(tb[RTA_DST]), 105 abuf, sizeof(abuf)), 106 r->rtm_dst_len 107 ); 108 } else { 109 fprintf(fp, "to %s ", format_host(r->rtm_family, 110 RTA_PAYLOAD(tb[RTA_DST]), 111 RTA_DATA(tb[RTA_DST]), 112 abuf, sizeof(abuf))); 113 } 114 } else if (r->rtm_dst_len) { 115 fprintf(fp, "to 0/%d ", r->rtm_dst_len); 116 } 117 118 if (r->rtm_tos) { 119 SPRINT_BUF(b1); 120 fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); 121 } 122 if (tb[RTA_PROTOINFO]) { 123 fprintf(fp, "fwmark %8x ", *(__u32*)RTA_DATA(tb[RTA_PROTOINFO])); 124 } 125 126 if (tb[RTA_IIF]) { 127 fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[RTA_IIF])); 128 } 129 130 if (r->rtm_table) 131 fprintf(fp, "lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1))); 132 133 if (tb[RTA_FLOW]) { 134 __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]); 135 __u32 from = to>>16; 136 to &= 0xFFFF; 137 if (from) { 138 fprintf(fp, "realms %s/", 139 rtnl_rtrealm_n2a(from, b1, sizeof(b1))); 140 } 141 fprintf(fp, "%s ", 142 rtnl_rtrealm_n2a(to, b1, sizeof(b1))); 143 } 144 145 if (r->rtm_type == RTN_NAT) { 146 if (tb[RTA_GATEWAY]) { 147 fprintf(fp, "map-to %s ", 148 format_host(r->rtm_family, 149 RTA_PAYLOAD(tb[RTA_GATEWAY]), 150 RTA_DATA(tb[RTA_GATEWAY]), 151 abuf, sizeof(abuf))); 152 } else 153 fprintf(fp, "masquerade"); 154 } else if (r->rtm_type != RTN_UNICAST) 155 fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); 156 157 fprintf(fp, "\n"); 158 fflush(fp); 159 return 0; 160} 161 162int iprule_list(int argc, char **argv) 163{ 164 struct rtnl_handle rth; 165 int af = preferred_family; 166 167 if (af == AF_UNSPEC) 168 af = AF_INET; 169 170 if (argc > 0) { 171 fprintf(stderr, "\"ip rule show\" need not eny arguments.\n"); 172 return -1; 173 } 174 175 if (rtnl_open(&rth, 0) < 0) 176 return 1; 177 178 if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { 179 perror("Cannot send dump request"); 180 return 1; 181 } 182 183 if (rtnl_dump_filter(&rth, print_rule, stdout, NULL, NULL) < 0) { 184 fprintf(stderr, "Dump terminated\n"); 185 return 1; 186 } 187 188 return 0; 189} 190 191 192int iprule_modify(int cmd, int argc, char **argv) 193{ 194 int table_ok = 0; 195 struct rtnl_handle rth; 196 struct { 197 struct nlmsghdr n; 198 struct rtmsg r; 199 char buf[1024]; 200 } req; 201 202 memset(&req, 0, sizeof(req)); 203 204 req.n.nlmsg_type = cmd; 205 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 206 req.n.nlmsg_flags = NLM_F_REQUEST; 207 req.r.rtm_family = preferred_family; 208 req.r.rtm_protocol = RTPROT_BOOT; 209 req.r.rtm_scope = RT_SCOPE_UNIVERSE; 210 req.r.rtm_table = 0; 211 req.r.rtm_type = RTN_UNSPEC; 212 213 if (cmd == RTM_NEWRULE) { 214 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; 215 req.r.rtm_type = RTN_UNICAST; 216 } 217 218 while (argc > 0) { 219 if (strcmp(*argv, "from") == 0) { 220 inet_prefix dst; 221 NEXT_ARG(); 222 get_prefix(&dst, *argv, req.r.rtm_family); 223 req.r.rtm_src_len = dst.bitlen; 224 addattr_l(&req.n, sizeof(req), RTA_SRC, &dst.data, dst.bytelen); 225 } else if (strcmp(*argv, "to") == 0) { 226 inet_prefix dst; 227 NEXT_ARG(); 228 get_prefix(&dst, *argv, req.r.rtm_family); 229 req.r.rtm_dst_len = dst.bitlen; 230 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); 231 } else if (matches(*argv, "preference") == 0 || 232 matches(*argv, "order") == 0 || 233 matches(*argv, "priority") == 0) { 234 __u32 pref; 235 NEXT_ARG(); 236 if (get_u32(&pref, *argv, 0)) 237 invarg("preference value is invalid\n", *argv); 238 addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref); 239 } else if (strcmp(*argv, "tos") == 0) { 240 __u32 tos; 241 NEXT_ARG(); 242 if (rtnl_dsfield_a2n(&tos, *argv)) 243 invarg("TOS value is invalid\n", *argv); 244 req.r.rtm_tos = tos; 245 } else if (strcmp(*argv, "fwmark") == 0) { 246 __u32 fwmark; 247 NEXT_ARG(); 248 if (get_u32(&fwmark, *argv, 16)) 249 invarg("fwmark value is invalid\n", *argv); 250 addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark); 251 } else if (matches(*argv, "realms") == 0) { 252 __u32 realm; 253 NEXT_ARG(); 254 if (get_rt_realms(&realm, *argv)) 255 invarg("invalid realms\n", *argv); 256 addattr32(&req.n, sizeof(req), RTA_FLOW, realm); 257 } else if (matches(*argv, "table") == 0 || 258 strcmp(*argv, "lookup") == 0) { 259 int tid; 260 NEXT_ARG(); 261 if (rtnl_rttable_a2n(&tid, *argv)) 262 invarg("invalid table ID\n", *argv); 263 req.r.rtm_table = tid; 264 table_ok = 1; 265 } else if (strcmp(*argv, "dev") == 0 || 266 strcmp(*argv, "iif") == 0) { 267 NEXT_ARG(); 268 addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1); 269 } else if (strcmp(*argv, "nat") == 0 || 270 matches(*argv, "map-to") == 0) { 271 NEXT_ARG(); 272 addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); 273 req.r.rtm_type = RTN_NAT; 274 } else { 275 int type; 276 277 if (strcmp(*argv, "type") == 0) { 278 NEXT_ARG(); 279 } 280 if (matches(*argv, "help") == 0) 281 usage(); 282 if (rtnl_rtntype_a2n(&type, *argv)) 283 invarg("Failed to parse rule type", *argv); 284 req.r.rtm_type = type; 285 } 286 argc--; 287 argv++; 288 } 289 290 if (req.r.rtm_family == AF_UNSPEC) 291 req.r.rtm_family = AF_INET; 292 293 if (!table_ok && cmd == RTM_NEWRULE) 294 req.r.rtm_table = RT_TABLE_MAIN; 295 296 if (rtnl_open(&rth, 0) < 0) 297 return 1; 298 299 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 300 return 2; 301 302 return 0; 303} 304 305int do_iprule(int argc, char **argv) 306{ 307 if (argc < 1) { 308 return iprule_list(0, NULL); 309 } else if (matches(argv[0], "list") == 0 || 310 matches(argv[0], "lst") == 0 || 311 matches(argv[0], "show") == 0) { 312 return iprule_list(argc-1, argv+1); 313 } else if (matches(argv[0], "add") == 0) { 314 return iprule_modify(RTM_NEWRULE, argc-1, argv+1); 315 } else if (matches(argv[0], "delete") == 0) { 316 return iprule_modify(RTM_DELRULE, argc-1, argv+1); 317 } else if (matches(argv[0], "help") == 0) 318 usage(); 319 320 fprintf(stderr, "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv); 321 exit(-1); 322} 323 324