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