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(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
     89   return NL_OK;
     90 }
     91 
     92 /* function: getinterface_ip
     93  * finds the first global non-privacy IP of the given family for the given interface, or returns NULL.  caller frees pointer
     94  * interface - interface to look for
     95  * family    - family
     96  */
     97 union anyip *getinterface_ip(const char *interface, int family) {
     98   struct ifaddrmsg ifa;
     99   struct nl_cb *callbacks = NULL;
    100   struct target targ;
    101   union anyip *retval = NULL;
    102 
    103   targ.family = family;
    104   targ.foundip = 0;
    105   targ.ifindex = if_nametoindex(interface);
    106   if(targ.ifindex == 0) {
    107     return NULL; // interface not found
    108   }
    109 
    110   memset(&ifa, 0, sizeof(ifa));
    111   ifa.ifa_family = targ.family;
    112 
    113   callbacks = nl_cb_alloc(NL_CB_DEFAULT);
    114   if(!callbacks) {
    115     goto cleanup;
    116   }
    117   nl_cb_set(callbacks, NL_CB_VALID, NL_CB_CUSTOM, getaddr_cb, &targ);
    118   nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, &targ);
    119 
    120   // sends message and waits for a response
    121   send_ifaddrmsg(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &ifa, callbacks);
    122 
    123   if(targ.foundip) {
    124     retval = malloc(sizeof(union anyip));
    125     if(!retval) {
    126       logmsg(ANDROID_LOG_FATAL,"getinterface_ip/out of memory");
    127       goto cleanup;
    128     }
    129     memcpy(retval, &targ.ip, sizeof(union anyip));
    130   }
    131 
    132 cleanup:
    133   if(callbacks)
    134     nl_cb_put(callbacks);
    135 
    136   return retval;
    137 }
    138