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