• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Daniel Drown <dan-android@drown.org>
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * setroute.c - network route configuration
17  */
18 #include <errno.h>
19 #include <netinet/in.h>
20 #include <net/if.h>
21 
22 #include <linux/netlink.h>
23 #include <linux/rtnetlink.h>
24 #include <netlink/handlers.h>
25 #include <netlink/msg.h>
26 #include <netlink-types.h>
27 
28 #include "netlink_msg.h"
29 #include "setroute.h"
30 #include "logging.h"
31 #include "getroute.h"
32 
33 /* function: if_route
34  * create/replace/delete a route
35  * ifname      - name of the outbound interface
36  * family      - AF_INET or AF_INET6
37  * destination - pointer to a struct in_addr or in6_addr for the destination network
38  * prefixlen   - bitlength of the network address (example: 24 for AF_INET's 255.255.255.0)
39  * gateway     - pointer to a struct in_addr or in6_addr for the gateway to use or NULL for an interface route
40  * metric      - route metric (lower is better)
41  * mtu         - route-specific mtu or 0 for the interface mtu
42  * change_type - ROUTE_DELETE, ROUTE_REPLACE, or ROUTE_CREATE
43  */
if_route(const char * ifname,int family,const void * destination,int prefixlen,const void * gateway,int metric,int mtu,int change_type)44 int if_route(const char *ifname, int family, const void *destination, int prefixlen, const void *gateway, int metric, int mtu, int change_type) {
45   int retval;
46   struct nl_msg *msg = NULL;
47   struct rtmsg rt;
48   uint16_t type, flags = 0;
49   size_t addr_size;
50   uint32_t ifindex;
51 
52   addr_size = inet_family_size(family);
53   if(addr_size == 0) {
54     retval = -EAFNOSUPPORT;
55     goto cleanup;
56   }
57 
58   if (!(ifindex = if_nametoindex(ifname))) {
59     retval = -ENODEV;
60     goto cleanup;
61   }
62 
63   memset(&rt, 0, sizeof(rt));
64   rt.rtm_family = family;
65   rt.rtm_table = RT_TABLE_MAIN;
66   rt.rtm_dst_len = prefixlen;
67   switch(change_type) {
68     case ROUTE_DELETE:
69       rt.rtm_scope = RT_SCOPE_NOWHERE;
70       type = RTM_DELROUTE;
71       break;
72 
73     case ROUTE_REPLACE:
74       flags = NLM_F_REPLACE;
75     case ROUTE_CREATE:
76       type = RTM_NEWROUTE;
77       flags |= NLM_F_CREATE;
78       if(gateway == NULL) {
79         rt.rtm_scope = RT_SCOPE_LINK;
80       } else {
81         rt.rtm_scope = RT_SCOPE_UNIVERSE;
82       }
83       rt.rtm_type = RTN_UNICAST;
84       //RTPROT_STATIC = from administrator's configuration
85       //RTPROT_BOOT = from an automatic process
86       rt.rtm_protocol = RTPROT_BOOT;
87       break;
88 
89     default:
90       retval = -EINVAL;
91       goto cleanup;
92   }
93 
94   flags |= NLM_F_REQUEST | NLM_F_ACK;
95 
96   msg = nlmsg_alloc_rtmsg(type, flags, &rt);
97   if(!msg) {
98     retval = -ENOMEM;
99     goto cleanup;
100   }
101 
102   if(nla_put(msg, RTA_DST, addr_size, destination) < 0) {
103     retval = -ENOMEM;
104     goto cleanup;
105   }
106   if(gateway != NULL)
107     if(nla_put(msg, RTA_GATEWAY, addr_size, gateway) < 0) {
108       retval = -ENOMEM;
109       goto cleanup;
110     }
111   if(nla_put(msg, RTA_OIF, 4, &ifindex) < 0) {
112     retval = -ENOMEM;
113     goto cleanup;
114   }
115   if(nla_put(msg, RTA_PRIORITY, 4, &metric) < 0) {
116     retval = -ENOMEM;
117     goto cleanup;
118   }
119   if(mtu > 0 && change_type != ROUTE_DELETE) {
120     // MTU is inside an RTA_METRICS nested message
121     struct nlattr *metrics = nla_nest_start(msg, RTA_METRICS);
122     if(metrics == NULL) {
123       retval = -ENOMEM;
124       goto cleanup;
125     }
126 
127     if(nla_put(msg, RTAX_MTU, 4, &mtu) < 0) {
128       retval = -ENOMEM;
129       goto cleanup;
130     }
131 
132     nla_nest_end(msg, metrics);
133   }
134 
135   retval = netlink_sendrecv(msg);
136 
137 cleanup:
138   if(msg)
139     nlmsg_free(msg);
140 
141   return retval;
142 }
143