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 32struct 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 */ 44static 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 */ 88static 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 */ 99union 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 134cleanup: 135 if(callbacks) 136 nl_cb_put(callbacks); 137 138 return retval; 139} 140