Home | History | Annotate | Download | only in ip
      1 /*
      2  * ipaddrlabel.c	"ip addrlabel"
      3  *
      4  * Copyright (C)2007 USAGI/WIDE Project
      5  *
      6  * This program is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation; either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program; if not, write to the Free Software
     18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19  *
     20  *
     21  * Based on iprule.c.
     22  *
     23  * Authors:	YOSHIFUJI Hideaki <yoshfuji (at) linux-ipv6.org>
     24  *
     25  */
     26 
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <unistd.h>
     30 #include <syslog.h>
     31 #include <fcntl.h>
     32 #include <sys/socket.h>
     33 #include <netinet/in.h>
     34 #include <netinet/ip.h>
     35 #include <arpa/inet.h>
     36 #include <string.h>
     37 #include <linux/types.h>
     38 #include <linux/if_addrlabel.h>
     39 
     40 #include "rt_names.h"
     41 #include "utils.h"
     42 #include "ip_common.h"
     43 
     44 #define IFAL_RTA(r)	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
     45 #define IFAL_PAYLOAD(n)	NLMSG_PAYLOAD(n,sizeof(struct ifaddrlblmsg))
     46 
     47 extern struct rtnl_handle rth;
     48 
     49 static void usage(void) __attribute__((noreturn));
     50 
     51 static void usage(void)
     52 {
     53 	fprintf(stderr, "Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]\n");
     54 	exit(-1);
     55 }
     56 
     57 int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
     58 {
     59 	FILE *fp = (FILE*)arg;
     60 	struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
     61 	int len = n->nlmsg_len;
     62 	int host_len = -1;
     63 	struct rtattr *tb[IFAL_MAX+1];
     64 	char abuf[256];
     65 
     66 	if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
     67 		return 0;
     68 
     69 	len -= NLMSG_LENGTH(sizeof(*ifal));
     70 	if (len < 0)
     71 		return -1;
     72 
     73 	parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
     74 
     75 	if (ifal->ifal_family == AF_INET)
     76 		host_len = 32;
     77 	else if (ifal->ifal_family == AF_INET6)
     78 		host_len = 128;
     79 
     80 	if (n->nlmsg_type == RTM_DELADDRLABEL)
     81 		fprintf(fp, "Deleted ");
     82 
     83 	if (tb[IFAL_ADDRESS]) {
     84 		fprintf(fp, "prefix %s/%u ",
     85 			format_host(ifal->ifal_family,
     86 				    RTA_PAYLOAD(tb[IFAL_ADDRESS]),
     87 				    RTA_DATA(tb[IFAL_ADDRESS]),
     88 				    abuf, sizeof(abuf)),
     89 			ifal->ifal_prefixlen);
     90 	}
     91 
     92 	if (ifal->ifal_index)
     93 		fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
     94 
     95 	if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(int32_t)) {
     96 		int32_t label;
     97 		memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
     98 		fprintf(fp, "label %d ", label);
     99 	}
    100 
    101 	fprintf(fp, "\n");
    102 	fflush(fp);
    103 	return 0;
    104 }
    105 
    106 static int ipaddrlabel_list(int argc, char **argv)
    107 {
    108 	int af = preferred_family;
    109 
    110 	if (af == AF_UNSPEC)
    111 		af = AF_INET6;
    112 
    113 	if (argc > 0) {
    114 		fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
    115 		return -1;
    116 	}
    117 
    118 	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
    119 		perror("Cannot send dump request");
    120 		return 1;
    121 	}
    122 
    123 	if (rtnl_dump_filter(&rth, print_addrlabel, stdout, NULL, NULL) < 0) {
    124 		fprintf(stderr, "Dump terminated\n");
    125 		return 1;
    126 	}
    127 
    128 	return 0;
    129 }
    130 
    131 
    132 static int ipaddrlabel_modify(int cmd, int argc, char **argv)
    133 {
    134 	struct {
    135 		struct nlmsghdr 	n;
    136 		struct ifaddrlblmsg	ifal;
    137 		char   			buf[1024];
    138 	} req;
    139 
    140 	inet_prefix prefix;
    141 	uint32_t label = 0xffffffffUL;
    142 	char *p = NULL;
    143 	char *l = NULL;
    144 
    145 	memset(&req, 0, sizeof(req));
    146 	memset(&prefix, 0, sizeof(prefix));
    147 
    148 	req.n.nlmsg_type = cmd;
    149 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
    150 	req.n.nlmsg_flags = NLM_F_REQUEST;
    151 	req.ifal.ifal_family = preferred_family;
    152 	req.ifal.ifal_prefixlen = 0;
    153 	req.ifal.ifal_index = 0;
    154 
    155 	if (cmd == RTM_NEWADDRLABEL) {
    156 		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
    157 	}
    158 
    159 	while (argc > 0) {
    160 		if (strcmp(*argv, "prefix") == 0) {
    161 			NEXT_ARG();
    162 			p = *argv;
    163 			get_prefix(&prefix, *argv, preferred_family);
    164 		} else if (strcmp(*argv, "dev") == 0) {
    165 			NEXT_ARG();
    166 			if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
    167 				invarg("dev is invalid\n", *argv);
    168 		} else if (strcmp(*argv, "label") == 0) {
    169 			NEXT_ARG();
    170 			l = *argv;
    171 			if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
    172 				invarg("label is invalid\n", *argv);
    173 		}
    174 		argc--;
    175 		argv++;
    176 	}
    177 	if (p == NULL) {
    178 		fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
    179 		return -1;
    180 	}
    181 	if (l == NULL) {
    182 		fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
    183 		return -1;
    184 	}
    185 	addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
    186 	addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
    187 	req.ifal.ifal_prefixlen = prefix.bitlen;
    188 
    189 	if (req.ifal.ifal_family == AF_UNSPEC)
    190 		req.ifal.ifal_family = AF_INET6;
    191 
    192 	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
    193 		return 2;
    194 
    195 	return 0;
    196 }
    197 
    198 
    199 static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
    200 {
    201 	struct rtnl_handle rth2;
    202 	struct rtmsg *r = NLMSG_DATA(n);
    203 	int len = n->nlmsg_len;
    204 	struct rtattr * tb[IFAL_MAX+1];
    205 
    206 	len -= NLMSG_LENGTH(sizeof(*r));
    207 	if (len < 0)
    208 		return -1;
    209 
    210 	parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
    211 
    212 	if (tb[IFAL_ADDRESS]) {
    213 		n->nlmsg_type = RTM_DELADDRLABEL;
    214 		n->nlmsg_flags = NLM_F_REQUEST;
    215 
    216 		if (rtnl_open(&rth2, 0) < 0)
    217 			return -1;
    218 
    219 		if (rtnl_talk(&rth2, n, 0, 0, NULL, NULL, NULL) < 0)
    220 			return -2;
    221 
    222 		rtnl_close(&rth2);
    223 	}
    224 
    225 	return 0;
    226 }
    227 
    228 static int ipaddrlabel_flush(int argc, char **argv)
    229 {
    230 	int af = preferred_family;
    231 
    232 	if (af == AF_UNSPEC)
    233 		af = AF_INET6;
    234 
    235 	if (argc > 0) {
    236 		fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
    237 		return -1;
    238 	}
    239 
    240 	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
    241 		perror("Cannot send dump request");
    242 		return 1;
    243 	}
    244 
    245 	if (rtnl_dump_filter(&rth, flush_addrlabel, NULL, NULL, NULL) < 0) {
    246 		fprintf(stderr, "Flush terminated\n");
    247 		return 1;
    248 	}
    249 
    250 	return 0;
    251 }
    252 
    253 int do_ipaddrlabel(int argc, char **argv)
    254 {
    255 	ll_init_map(&rth);
    256 
    257 	if (argc < 1) {
    258 		return ipaddrlabel_list(0, NULL);
    259 	} else if (matches(argv[0], "list") == 0 ||
    260 		   matches(argv[0], "show") == 0) {
    261 		return ipaddrlabel_list(argc-1, argv+1);
    262 	} else if (matches(argv[0], "add") == 0) {
    263 		return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
    264 	} else if (matches(argv[0], "delete") == 0) {
    265 		return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
    266 	} else if (matches(argv[0], "flush") == 0) {
    267 		return ipaddrlabel_flush(argc-1, argv+1);
    268 	} else if (matches(argv[0], "help") == 0)
    269 		usage();
    270 
    271 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
    272 	exit(-1);
    273 }
    274 
    275