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