1 /* 2 * Copyright 2012 Daniel Drown <dan-android (at) 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 */ 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