Home | History | Annotate | Download | only in android-clat
      1 /*
      2  * Copyright 2012 Daniel Drown
      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  * getaddr.c - get a locally configured address
     17  */
     18 #include <netinet/in.h>
     19 #include <strings.h>
     20 #include <string.h>
     21 #include <net/if.h>
     22 
     23 #include <linux/if_addr.h>
     24 #include <linux/rtnetlink.h>
     25 #include <netlink/handlers.h>
     26 #include <netlink/msg.h>
     27 
     28 #include "getaddr.h"
     29 #include "netlink_msg.h"
     30 #include "logging.h"
     31 
     32 // shared state between getinterface_ip and getaddr_cb
     33 struct target {
     34   int family;
     35   unsigned int ifindex;
     36   union anyip ip;
     37   int foundip;
     38 };
     39 
     40 /* function: getaddr_cb
     41  * callback for getinterface_ip
     42  * msg  - netlink message
     43  * data - (struct target) info for which address we're looking for
     44  */
     45 static int getaddr_cb(struct nl_msg *msg, void *data) {
     46   struct ifaddrmsg *ifa_p;
     47   struct rtattr *rta_p;
     48   int rta_len;
     49   struct target *targ_p = (struct target *)data;
     50 
     51   ifa_p = (struct ifaddrmsg *)nlmsg_data(nlmsg_hdr(msg));
     52   rta_p = (struct rtattr *)IFA_RTA(ifa_p);
     53 
     54   if(ifa_p->ifa_index != targ_p->ifindex)
     55     return NL_OK;
     56 
     57   if(ifa_p->ifa_scope != RT_SCOPE_UNIVERSE)
     58     return NL_OK;
     59 
     60   rta_len = RTM_PAYLOAD(nlmsg_hdr(msg));
     61   for (; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) {
     62     switch(rta_p->rta_type) {
     63       case IFA_ADDRESS:
     64         if((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) {
     65           memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
     66           targ_p->foundip = 1;
     67           return NL_OK;
     68         }
     69         break;
     70       case IFA_LOCAL:
     71         if(targ_p->family == AF_INET) {
     72           memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
     73           targ_p->foundip = 1;
     74           return NL_OK;
     75         }
     76         break;
     77     }
     78   }
     79 
     80   return NL_OK;
     81 }
     82 
     83 /* function: error_handler
     84  * error callback for getinterface_ip
     85  * nla  - source of the error message
     86  * err  - netlink message
     87  * arg  - (struct target) info for which address we're looking for
     88  */
     89 static int error_handler(__attribute__((unused)) struct sockaddr_nl *nla,
     90                          __attribute__((unused)) struct nlmsgerr *err,
     91                          __attribute__((unused)) void *arg) {
     92   return NL_OK;
     93 }
     94 
     95 /* function: getinterface_ip
     96  * finds the first global non-privacy IP of the given family for the given interface, or returns NULL.  caller frees pointer
     97  * interface - interface to look for
     98  * family    - family
     99  */
    100 union anyip *getinterface_ip(const char *interface, int family) {
    101   struct ifaddrmsg ifa;
    102   struct nl_cb *callbacks = NULL;
    103   struct target targ;
    104   union anyip *retval = NULL;
    105 
    106   targ.family = family;
    107   targ.foundip = 0;
    108   targ.ifindex = if_nametoindex(interface);
    109   if(targ.ifindex == 0) {
    110     return NULL; // interface not found
    111   }
    112 
    113   memset(&ifa, 0, sizeof(ifa));
    114   ifa.ifa_family = targ.family;
    115 
    116   callbacks = nl_cb_alloc(NL_CB_DEFAULT);
    117   if(!callbacks) {
    118     goto cleanup;
    119   }
    120   nl_cb_set(callbacks, NL_CB_VALID, NL_CB_CUSTOM, getaddr_cb, &targ);
    121   nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, &targ);
    122 
    123   // sends message and waits for a response
    124   send_ifaddrmsg(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &ifa, callbacks);
    125 
    126   if(targ.foundip) {
    127     retval = malloc(sizeof(union anyip));
    128     if(!retval) {
    129       logmsg(ANDROID_LOG_FATAL,"getinterface_ip/out of memory");
    130       goto cleanup;
    131     }
    132     memcpy(retval, &targ.ip, sizeof(union anyip));
    133   }
    134 
    135 cleanup:
    136   if(callbacks)
    137     nl_cb_put(callbacks);
    138 
    139   return retval;
    140 }
    141