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, see <http://www.gnu.org/licenses>.
     18  *
     19  *
     20  * Based on iprule.c.
     21  *
     22  * Authors:	YOSHIFUJI Hideaki <yoshfuji (at) linux-ipv6.org>
     23  *
     24  */
     25 
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <unistd.h>
     29 #include <syslog.h>
     30 #include <fcntl.h>
     31 #include <sys/socket.h>
     32 #include <netinet/in.h>
     33 #include <netinet/ip.h>
     34 #include <arpa/inet.h>
     35 #include <string.h>
     36 #include <linux/types.h>
     37 #include <linux/if_addrlabel.h>
     38 
     39 #include "rt_names.h"
     40 #include "utils.h"
     41 #include "ip_common.h"
     42 
     43 #define IFAL_RTA(r)	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
     44 #define IFAL_PAYLOAD(n)	NLMSG_PAYLOAD(n,sizeof(struct ifaddrlblmsg))
     45 
     46 extern struct rtnl_handle rth;
     47 
     48 static void usage(void) __attribute__((noreturn));
     49 
     50 static void usage(void)
     51 {
     52 	fprintf(stderr, "Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]\n");
     53 	exit(-1);
     54 }
     55 
     56 int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
     57 {
     58 	FILE *fp = (FILE*)arg;
     59 	struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
     60 	int len = n->nlmsg_len;
     61 	struct rtattr *tb[IFAL_MAX+1];
     62 	char abuf[256];
     63 
     64 	if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
     65 		return 0;
     66 
     67 	len -= NLMSG_LENGTH(sizeof(*ifal));
     68 	if (len < 0)
     69 		return -1;
     70 
     71 	parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
     72 
     73 	if (n->nlmsg_type == RTM_DELADDRLABEL)
     74 		fprintf(fp, "Deleted ");
     75 
     76 	if (tb[IFAL_ADDRESS]) {
     77 		fprintf(fp, "prefix %s/%u ",
     78 			format_host(ifal->ifal_family,
     79 				    RTA_PAYLOAD(tb[IFAL_ADDRESS]),
     80 				    RTA_DATA(tb[IFAL_ADDRESS]),
     81 				    abuf, sizeof(abuf)),
     82 			ifal->ifal_prefixlen);
     83 	}
     84 
     85 	if (ifal->ifal_index)
     86 		fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
     87 
     88 	if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) {
     89 		uint32_t label;
     90 		memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
     91 		fprintf(fp, "label %u ", label);
     92 	}
     93 
     94 	fprintf(fp, "\n");
     95 	fflush(fp);
     96 	return 0;
     97 }
     98 
     99 static int ipaddrlabel_list(int argc, char **argv)
    100 {
    101 	int af = preferred_family;
    102 
    103 	if (af == AF_UNSPEC)
    104 		af = AF_INET6;
    105 
    106 	if (argc > 0) {
    107 		fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
    108 		return -1;
    109 	}
    110 
    111 	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
    112 		perror("Cannot send dump request");
    113 		return 1;
    114 	}
    115 
    116 	if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
    117 		fprintf(stderr, "Dump terminated\n");
    118 		return 1;
    119 	}
    120 
    121 	return 0;
    122 }
    123 
    124 
    125 static int ipaddrlabel_modify(int cmd, int argc, char **argv)
    126 {
    127 	struct {
    128 		struct nlmsghdr	n;
    129 		struct ifaddrlblmsg	ifal;
    130 		char  			buf[1024];
    131 	} req;
    132 
    133 	inet_prefix prefix;
    134 	uint32_t label = 0xffffffffUL;
    135 	char *p = NULL;
    136 	char *l = NULL;
    137 
    138 	memset(&req, 0, sizeof(req));
    139 	memset(&prefix, 0, sizeof(prefix));
    140 
    141 	req.n.nlmsg_type = cmd;
    142 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
    143 	req.n.nlmsg_flags = NLM_F_REQUEST;
    144 	req.ifal.ifal_family = preferred_family;
    145 	req.ifal.ifal_prefixlen = 0;
    146 	req.ifal.ifal_index = 0;
    147 
    148 	if (cmd == RTM_NEWADDRLABEL) {
    149 		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
    150 	}
    151 
    152 	while (argc > 0) {
    153 		if (strcmp(*argv, "prefix") == 0) {
    154 			NEXT_ARG();
    155 			p = *argv;
    156 			get_prefix(&prefix, *argv, preferred_family);
    157 		} else if (strcmp(*argv, "dev") == 0) {
    158 			NEXT_ARG();
    159 			if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
    160 				invarg("dev is invalid\n", *argv);
    161 		} else if (strcmp(*argv, "label") == 0) {
    162 			NEXT_ARG();
    163 			l = *argv;
    164 			if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
    165 				invarg("label is invalid\n", *argv);
    166 		}
    167 		argc--;
    168 		argv++;
    169 	}
    170 	if (p == NULL) {
    171 		fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
    172 		return -1;
    173 	}
    174 	if (l == NULL) {
    175 		fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
    176 		return -1;
    177 	}
    178 	addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
    179 	addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
    180 	req.ifal.ifal_prefixlen = prefix.bitlen;
    181 
    182 	if (req.ifal.ifal_family == AF_UNSPEC)
    183 		req.ifal.ifal_family = AF_INET6;
    184 
    185 	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
    186 		return -2;
    187 
    188 	return 0;
    189 }
    190 
    191 
    192 static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
    193 {
    194 	struct rtnl_handle rth2;
    195 	struct rtmsg *r = NLMSG_DATA(n);
    196 	int len = n->nlmsg_len;
    197 	struct rtattr * tb[IFAL_MAX+1];
    198 
    199 	len -= NLMSG_LENGTH(sizeof(*r));
    200 	if (len < 0)
    201 		return -1;
    202 
    203 	parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
    204 
    205 	if (tb[IFAL_ADDRESS]) {
    206 		n->nlmsg_type = RTM_DELADDRLABEL;
    207 		n->nlmsg_flags = NLM_F_REQUEST;
    208 
    209 		if (rtnl_open(&rth2, 0) < 0)
    210 			return -1;
    211 
    212 		if (rtnl_talk(&rth2, n, NULL, 0) < 0)
    213 			return -2;
    214 
    215 		rtnl_close(&rth2);
    216 	}
    217 
    218 	return 0;
    219 }
    220 
    221 static int ipaddrlabel_flush(int argc, char **argv)
    222 {
    223 	int af = preferred_family;
    224 
    225 	if (af == AF_UNSPEC)
    226 		af = AF_INET6;
    227 
    228 	if (argc > 0) {
    229 		fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
    230 		return -1;
    231 	}
    232 
    233 	if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
    234 		perror("Cannot send dump request");
    235 		return -1;
    236 	}
    237 
    238 	if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) {
    239 		fprintf(stderr, "Flush terminated\n");
    240 		return -1;
    241 	}
    242 
    243 	return 0;
    244 }
    245 
    246 int do_ipaddrlabel(int argc, char **argv)
    247 {
    248 	if (argc < 1) {
    249 		return ipaddrlabel_list(0, NULL);
    250 	} else if (matches(argv[0], "list") == 0 ||
    251 		   matches(argv[0], "lst") == 0 ||
    252 		   matches(argv[0], "show") == 0) {
    253 		return ipaddrlabel_list(argc-1, argv+1);
    254 	} else if (matches(argv[0], "add") == 0) {
    255 		return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
    256 	} else if (matches(argv[0], "delete") == 0) {
    257 		return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
    258 	} else if (matches(argv[0], "flush") == 0) {
    259 		return ipaddrlabel_flush(argc-1, argv+1);
    260 	} else if (matches(argv[0], "help") == 0)
    261 		usage();
    262 
    263 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
    264 	exit(-1);
    265 }
    266