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 	struct rtattr *tb[IFAL_MAX+1];
     63 	char abuf[256];
     64 
     65 	if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
     66 		return 0;
     67 
     68 	len -= NLMSG_LENGTH(sizeof(*ifal));
     69 	if (len < 0)
     70 		return -1;
     71 
     72 	parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
     73 
     74 	if (n->nlmsg_type == RTM_DELADDRLABEL)
     75 		fprintf(fp, "Deleted ");
     76 
     77 	if (tb[IFAL_ADDRESS]) {
     78 		fprintf(fp, "prefix %s/%u ",
     79 			format_host(ifal->ifal_family,
     80 				    RTA_PAYLOAD(tb[IFAL_ADDRESS]),
     81 				    RTA_DATA(tb[IFAL_ADDRESS]),
     82 				    abuf, sizeof(abuf)),
     83 			ifal->ifal_prefixlen);
     84 	}
     85 
     86 	if (ifal->ifal_index)
     87 		fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
     88 
     89 	if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(int32_t)) {
     90 		int32_t label;
     91 		memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
     92 		fprintf(fp, "label %d ", label);
     93 	}
     94 
     95 	fprintf(fp, "\n");
     96 	fflush(fp);
     97 	return 0;
     98 }
     99 
    100 static int ipaddrlabel_list(int argc, char **argv)
    101 {
    102 	int af = preferred_family;
    103 
    104 	if (af == AF_UNSPEC)
    105 		af = AF_INET6;
    106 
    107 	if (argc > 0) {
    108 		fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
    109 		return -1;
    110 	}
    111 
    112 	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
    113 		perror("Cannot send dump request");
    114 		return 1;
    115 	}
    116 
    117 	if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
    118 		fprintf(stderr, "Dump terminated\n");
    119 		return 1;
    120 	}
    121 
    122 	return 0;
    123 }
    124 
    125 
    126 static int ipaddrlabel_modify(int cmd, int argc, char **argv)
    127 {
    128 	struct {
    129 		struct nlmsghdr 	n;
    130 		struct ifaddrlblmsg	ifal;
    131 		char   			buf[1024];
    132 	} req;
    133 
    134 	inet_prefix prefix;
    135 	uint32_t label = 0xffffffffUL;
    136 	char *p = NULL;
    137 	char *l = NULL;
    138 
    139 	memset(&req, 0, sizeof(req));
    140 	memset(&prefix, 0, sizeof(prefix));
    141 
    142 	req.n.nlmsg_type = cmd;
    143 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
    144 	req.n.nlmsg_flags = NLM_F_REQUEST;
    145 	req.ifal.ifal_family = preferred_family;
    146 	req.ifal.ifal_prefixlen = 0;
    147 	req.ifal.ifal_index = 0;
    148 
    149 	if (cmd == RTM_NEWADDRLABEL) {
    150 		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
    151 	}
    152 
    153 	while (argc > 0) {
    154 		if (strcmp(*argv, "prefix") == 0) {
    155 			NEXT_ARG();
    156 			p = *argv;
    157 			get_prefix(&prefix, *argv, preferred_family);
    158 		} else if (strcmp(*argv, "dev") == 0) {
    159 			NEXT_ARG();
    160 			if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
    161 				invarg("dev is invalid\n", *argv);
    162 		} else if (strcmp(*argv, "label") == 0) {
    163 			NEXT_ARG();
    164 			l = *argv;
    165 			if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
    166 				invarg("label is invalid\n", *argv);
    167 		}
    168 		argc--;
    169 		argv++;
    170 	}
    171 	if (p == NULL) {
    172 		fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
    173 		return -1;
    174 	}
    175 	if (l == NULL) {
    176 		fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
    177 		return -1;
    178 	}
    179 	addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
    180 	addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
    181 	req.ifal.ifal_prefixlen = prefix.bitlen;
    182 
    183 	if (req.ifal.ifal_family == AF_UNSPEC)
    184 		req.ifal.ifal_family = AF_INET6;
    185 
    186 	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
    187 		return 2;
    188 
    189 	return 0;
    190 }
    191 
    192 
    193 static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
    194 {
    195 	struct rtnl_handle rth2;
    196 	struct rtmsg *r = NLMSG_DATA(n);
    197 	int len = n->nlmsg_len;
    198 	struct rtattr * tb[IFAL_MAX+1];
    199 
    200 	len -= NLMSG_LENGTH(sizeof(*r));
    201 	if (len < 0)
    202 		return -1;
    203 
    204 	parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
    205 
    206 	if (tb[IFAL_ADDRESS]) {
    207 		n->nlmsg_type = RTM_DELADDRLABEL;
    208 		n->nlmsg_flags = NLM_F_REQUEST;
    209 
    210 		if (rtnl_open(&rth2, 0) < 0)
    211 			return -1;
    212 
    213 		if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0)
    214 			return -2;
    215 
    216 		rtnl_close(&rth2);
    217 	}
    218 
    219 	return 0;
    220 }
    221 
    222 static int ipaddrlabel_flush(int argc, char **argv)
    223 {
    224 	int af = preferred_family;
    225 
    226 	if (af == AF_UNSPEC)
    227 		af = AF_INET6;
    228 
    229 	if (argc > 0) {
    230 		fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
    231 		return -1;
    232 	}
    233 
    234 	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
    235 		perror("Cannot send dump request");
    236 		return 1;
    237 	}
    238 
    239 	if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) {
    240 		fprintf(stderr, "Flush terminated\n");
    241 		return 1;
    242 	}
    243 
    244 	return 0;
    245 }
    246 
    247 int do_ipaddrlabel(int argc, char **argv)
    248 {
    249 	ll_init_map(&rth);
    250 
    251 	if (argc < 1) {
    252 		return ipaddrlabel_list(0, NULL);
    253 	} else if (matches(argv[0], "list") == 0 ||
    254 		   matches(argv[0], "show") == 0) {
    255 		return ipaddrlabel_list(argc-1, argv+1);
    256 	} else if (matches(argv[0], "add") == 0) {
    257 		return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
    258 	} else if (matches(argv[0], "delete") == 0) {
    259 		return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
    260 	} else if (matches(argv[0], "flush") == 0) {
    261 		return ipaddrlabel_flush(argc-1, argv+1);
    262 	} else if (matches(argv[0], "help") == 0)
    263 		usage();
    264 
    265 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
    266 	exit(-1);
    267 }
    268 
    269