Home | History | Annotate | Download | only in ip
      1 /*
      2  * ipnetconf.c		"ip netconf".
      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:	Nicolas Dichtel, <nicolas.dichtel (at) 6wind.com>
     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 <string.h>
     19 #include <sys/time.h>
     20 #include <sys/socket.h>
     21 #include <netinet/in.h>
     22 
     23 #include "rt_names.h"
     24 #include "utils.h"
     25 #include "ip_common.h"
     26 
     27 static struct
     28 {
     29 	int family;
     30 	int ifindex;
     31 } filter;
     32 
     33 static void usage(void) __attribute__((noreturn));
     34 
     35 static void usage(void)
     36 {
     37 	fprintf(stderr, "Usage: ip netconf show [ dev STRING ]\n");
     38 	exit(-1);
     39 }
     40 
     41 #define NETCONF_RTA(r)	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg))))
     42 
     43 int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
     44 		  struct nlmsghdr *n, void *arg)
     45 {
     46 	FILE *fp = (FILE*)arg;
     47 	struct netconfmsg *ncm = NLMSG_DATA(n);
     48 	int len = n->nlmsg_len;
     49 	struct rtattr *tb[NETCONFA_MAX+1];
     50 
     51 	if (n->nlmsg_type == NLMSG_ERROR)
     52 		return -1;
     53 	if (n->nlmsg_type != RTM_NEWNETCONF) {
     54 		fprintf(stderr, "Not RTM_NEWNETCONF: %08x %08x %08x\n",
     55 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
     56 
     57 		return -1;
     58 	}
     59 	len -= NLMSG_SPACE(sizeof(*ncm));
     60 	if (len < 0) {
     61 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
     62 		return -1;
     63 	}
     64 
     65 	if (filter.family && filter.family != ncm->ncm_family)
     66 		return 0;
     67 
     68 	parse_rtattr(tb, NETCONFA_MAX, NETCONF_RTA(ncm),
     69 		     NLMSG_PAYLOAD(n, sizeof(*ncm)));
     70 
     71 	switch (ncm->ncm_family) {
     72 	case AF_INET:
     73 		fprintf(fp, "ipv4 ");
     74 		break;
     75 	case AF_INET6:
     76 		fprintf(fp, "ipv6 ");
     77 		break;
     78 	default:
     79 		fprintf(fp, "unknown ");
     80 		break;
     81 	}
     82 
     83 	if (tb[NETCONFA_IFINDEX]) {
     84 		int *ifindex = (int *)RTA_DATA(tb[NETCONFA_IFINDEX]);
     85 
     86 		switch (*ifindex) {
     87 		case NETCONFA_IFINDEX_ALL:
     88 			fprintf(fp, "all ");
     89 			break;
     90 		case NETCONFA_IFINDEX_DEFAULT:
     91 			fprintf(fp, "default ");
     92 			break;
     93 		default:
     94 			fprintf(fp, "dev %s ", ll_index_to_name(*ifindex));
     95 			break;
     96 		}
     97 	}
     98 
     99 	if (tb[NETCONFA_FORWARDING])
    100 		fprintf(fp, "forwarding %s ",
    101 			*(int *)RTA_DATA(tb[NETCONFA_FORWARDING])?"on":"off");
    102 	if (tb[NETCONFA_RP_FILTER]) {
    103 		int rp_filter = *(int *)RTA_DATA(tb[NETCONFA_RP_FILTER]);
    104 
    105 		if (rp_filter == 0)
    106 			fprintf(fp, "rp_filter off ");
    107 		else if (rp_filter == 1)
    108 			fprintf(fp, "rp_filter strict ");
    109 		else if (rp_filter == 2)
    110 			fprintf(fp, "rp_filter loose ");
    111 		else
    112 			fprintf(fp, "rp_filter unknown mode ");
    113 	}
    114 	if (tb[NETCONFA_MC_FORWARDING])
    115 		fprintf(fp, "mc_forwarding %d ",
    116 			*(int *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]));
    117 
    118 	if (tb[NETCONFA_PROXY_NEIGH])
    119 		fprintf(fp, "proxy_neigh %s ",
    120 			*(int *)RTA_DATA(tb[NETCONFA_PROXY_NEIGH])?"on":"off");
    121 
    122 	fprintf(fp, "\n");
    123 	fflush(fp);
    124 	return 0;
    125 }
    126 
    127 static int print_netconf2(const struct sockaddr_nl *who,
    128 			  struct nlmsghdr *n, void *arg)
    129 {
    130 	return print_netconf(who, NULL, n, arg);
    131 }
    132 
    133 void ipnetconf_reset_filter(int ifindex)
    134 {
    135 	memset(&filter, 0, sizeof(filter));
    136 	filter.ifindex = ifindex;
    137 }
    138 
    139 static int do_show(int argc, char **argv)
    140 {
    141 	struct {
    142 		struct nlmsghdr		n;
    143 		struct netconfmsg	ncm;
    144 		char			buf[1024];
    145 	} req;
    146 
    147 	ipnetconf_reset_filter(0);
    148 	filter.family = preferred_family;
    149 	if (filter.family == AF_UNSPEC)
    150 		filter.family = AF_INET;
    151 
    152 	while (argc > 0) {
    153 		if (strcmp(*argv, "dev") == 0) {
    154 			NEXT_ARG();
    155 			filter.ifindex = ll_name_to_index(*argv);
    156 			if (filter.ifindex <= 0) {
    157 				fprintf(stderr, "Device \"%s\" does not exist.\n",
    158 					*argv);
    159 				return -1;
    160 			}
    161 		}
    162 		argv++; argc--;
    163 	}
    164 
    165 	ll_init_map(&rth);
    166 	if (filter.ifindex) {
    167 		memset(&req, 0, sizeof(req));
    168 		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg));
    169 		req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
    170 		req.n.nlmsg_type = RTM_GETNETCONF;
    171 		req.ncm.ncm_family = filter.family;
    172 		if (filter.ifindex)
    173 			addattr_l(&req.n, sizeof(req), NETCONFA_IFINDEX,
    174 				  &filter.ifindex, sizeof(filter.ifindex));
    175 
    176 		if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
    177 			perror("Can not send request");
    178 			exit(1);
    179 		}
    180 		rtnl_listen(&rth, print_netconf, stdout);
    181 	} else {
    182 dump:
    183 		if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) {
    184 			perror("Cannot send dump request");
    185 			exit(1);
    186 		}
    187 		if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) {
    188 			fprintf(stderr, "Dump terminated\n");
    189 			exit(1);
    190 		}
    191 		if (preferred_family == AF_UNSPEC) {
    192 			preferred_family = AF_INET6;
    193 			filter.family = AF_INET6;
    194 			goto dump;
    195 		}
    196 	}
    197 	return 0;
    198 }
    199 
    200 int do_ipnetconf(int argc, char **argv)
    201 {
    202 	if (argc > 0) {
    203 		if (matches(*argv, "show") == 0 ||
    204 		    matches(*argv, "lst") == 0 ||
    205 		    matches(*argv, "list") == 0)
    206 			return do_show(argc-1, argv+1);
    207 		if (matches(*argv, "help") == 0)
    208 			usage();
    209 	} else
    210 		return do_show(0, NULL);
    211 
    212 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip netconf help\".\n", *argv);
    213 	exit(-1);
    214 }
    215