Home | History | Annotate | Download | only in android-clat
      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