blob: cffee9fb99d322b57669fa51bb776e18e3b84c04 [file] [log] [blame]
Daniel Drowna45056e2012-03-23 10:42:54 -05001/*
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>
Daniel Drowna45056e2012-03-23 10:42:54 -050026
27#include "netlink_msg.h"
28#include "setroute.h"
29#include "logging.h"
30#include "getroute.h"
31
32/* function: if_route
33 * create/replace/delete a route
34 * ifname - name of the outbound interface
35 * family - AF_INET or AF_INET6
36 * destination - pointer to a struct in_addr or in6_addr for the destination network
37 * prefixlen - bitlength of the network address (example: 24 for AF_INET's 255.255.255.0)
38 * gateway - pointer to a struct in_addr or in6_addr for the gateway to use or NULL for an interface route
39 * metric - route metric (lower is better)
40 * mtu - route-specific mtu or 0 for the interface mtu
41 * change_type - ROUTE_DELETE, ROUTE_REPLACE, or ROUTE_CREATE
42 */
43int if_route(const char *ifname, int family, const void *destination, int prefixlen, const void *gateway, int metric, int mtu, int change_type) {
44 int retval;
45 struct nl_msg *msg = NULL;
46 struct rtmsg rt;
47 uint16_t type, flags = 0;
48 size_t addr_size;
49 uint32_t ifindex;
50
51 addr_size = inet_family_size(family);
52 if(addr_size == 0) {
53 retval = -EAFNOSUPPORT;
54 goto cleanup;
55 }
56
57 if (!(ifindex = if_nametoindex(ifname))) {
58 retval = -ENODEV;
59 goto cleanup;
60 }
61
62 memset(&rt, 0, sizeof(rt));
63 rt.rtm_family = family;
64 rt.rtm_table = RT_TABLE_MAIN;
65 rt.rtm_dst_len = prefixlen;
66 switch(change_type) {
67 case ROUTE_DELETE:
68 rt.rtm_scope = RT_SCOPE_NOWHERE;
69 type = RTM_DELROUTE;
70 break;
71
72 case ROUTE_REPLACE:
73 flags = NLM_F_REPLACE;
74 case ROUTE_CREATE:
75 type = RTM_NEWROUTE;
76 flags |= NLM_F_CREATE;
77 if(gateway == NULL) {
78 rt.rtm_scope = RT_SCOPE_LINK;
79 } else {
80 rt.rtm_scope = RT_SCOPE_UNIVERSE;
81 }
82 rt.rtm_type = RTN_UNICAST;
83 //RTPROT_STATIC = from administrator's configuration
84 //RTPROT_BOOT = from an automatic process
85 rt.rtm_protocol = RTPROT_BOOT;
86 break;
87
88 default:
89 retval = -EINVAL;
90 goto cleanup;
91 }
92
93 flags |= NLM_F_REQUEST | NLM_F_ACK;
94
95 msg = nlmsg_alloc_rtmsg(type, flags, &rt);
96 if(!msg) {
97 retval = -ENOMEM;
98 goto cleanup;
99 }
100
101 if(nla_put(msg, RTA_DST, addr_size, destination) < 0) {
102 retval = -ENOMEM;
103 goto cleanup;
104 }
105 if(gateway != NULL)
106 if(nla_put(msg, RTA_GATEWAY, addr_size, gateway) < 0) {
107 retval = -ENOMEM;
108 goto cleanup;
109 }
110 if(nla_put(msg, RTA_OIF, 4, &ifindex) < 0) {
111 retval = -ENOMEM;
112 goto cleanup;
113 }
114 if(nla_put(msg, RTA_PRIORITY, 4, &metric) < 0) {
115 retval = -ENOMEM;
116 goto cleanup;
117 }
118 if(mtu > 0 && change_type != ROUTE_DELETE) {
119 // MTU is inside an RTA_METRICS nested message
120 struct nlattr *metrics = nla_nest_start(msg, RTA_METRICS);
121 if(metrics == NULL) {
122 retval = -ENOMEM;
123 goto cleanup;
124 }
125
126 if(nla_put(msg, RTAX_MTU, 4, &mtu) < 0) {
127 retval = -ENOMEM;
128 goto cleanup;
129 }
130
131 nla_nest_end(msg, metrics);
132 }
133
134 retval = netlink_sendrecv(msg);
135
136cleanup:
137 if(msg)
138 nlmsg_free(msg);
139
140 return retval;
141}