1a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* 2a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Copyright 2012 Daniel Drown 3a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 4a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Licensed under the Apache License, Version 2.0 (the "License"); 5a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * you may not use this file except in compliance with the License. 6a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * You may obtain a copy of the License at 7a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 8a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * http://www.apache.org/licenses/LICENSE-2.0 9a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 10a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Unless required by applicable law or agreed to in writing, software 11a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * distributed under the License is distributed on an "AS IS" BASIS, 12a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * See the License for the specific language governing permissions and 14a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * limitations under the License. 15a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 16a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * getaddr.c - get a locally configured address 17a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 18a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/in.h> 19a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <strings.h> 20a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <string.h> 21a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <net/if.h> 22a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 23c2f9edd16daf2752bbec4949f513df2e42fdc5c3Paul Stewart#include <linux/if_addr.h> 24a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <linux/rtnetlink.h> 25a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/handlers.h> 26a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/msg.h> 27a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 28a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "getaddr.h" 29a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "netlink_msg.h" 30a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "logging.h" 31a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 32a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown// shared state between getinterface_ip and getaddr_cb 33a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstruct target { 34a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown int family; 35a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown unsigned int ifindex; 36a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown union anyip ip; 37a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown int foundip; 38a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown}; 39a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 40a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: getaddr_cb 41a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * callback for getinterface_ip 42a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * msg - netlink message 43a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * data - (struct target) info for which address we're looking for 44a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 45a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstatic int getaddr_cb(struct nl_msg *msg, void *data) { 46a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct ifaddrmsg *ifa_p; 47a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct rtattr *rta_p; 48a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown int rta_len; 49a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct target *targ_p = (struct target *)data; 50a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 51a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown ifa_p = (struct ifaddrmsg *)nlmsg_data(nlmsg_hdr(msg)); 52a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown rta_p = (struct rtattr *)IFA_RTA(ifa_p); 53a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 54a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(ifa_p->ifa_index != targ_p->ifindex) 55a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 56a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 57a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) 58a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 59a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 60a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown rta_len = RTM_PAYLOAD(nlmsg_hdr(msg)); 61a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown for (; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) { 62a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown switch(rta_p->rta_type) { 63a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown case IFA_ADDRESS: 64a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) { 65a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr)); 66a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ_p->foundip = 1; 67a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 68a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 69a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown break; 70a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown case IFA_LOCAL: 71a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(targ_p->family == AF_INET) { 72a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr)); 73a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ_p->foundip = 1; 74a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 75a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 76a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown break; 77a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 78a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 79a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 80a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 81a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 82a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 83a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: error_handler 84a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * error callback for getinterface_ip 85a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * nla - source of the error message 86a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * err - netlink message 87a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * arg - (struct target) info for which address we're looking for 88a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 8956ec161d47856212008f47676577882f30853312Lorenzo Colittistatic int error_handler(__attribute__((unused)) struct sockaddr_nl *nla, 9056ec161d47856212008f47676577882f30853312Lorenzo Colitti __attribute__((unused)) struct nlmsgerr *err, 9156ec161d47856212008f47676577882f30853312Lorenzo Colitti __attribute__((unused)) void *arg) { 92a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 93a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 94a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 95a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: getinterface_ip 96a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * finds the first global non-privacy IP of the given family for the given interface, or returns NULL. caller frees pointer 97a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * interface - interface to look for 98a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * family - family 99a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 100a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownunion anyip *getinterface_ip(const char *interface, int family) { 101a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct ifaddrmsg ifa; 102a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct nl_cb *callbacks = NULL; 103a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct target targ; 104a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown union anyip *retval = NULL; 105a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 106a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ.family = family; 107a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ.foundip = 0; 108a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ.ifindex = if_nametoindex(interface); 109a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(targ.ifindex == 0) { 110a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NULL; // interface not found 111a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 112a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 113a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memset(&ifa, 0, sizeof(ifa)); 114a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown ifa.ifa_family = targ.family; 115a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 116a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown callbacks = nl_cb_alloc(NL_CB_DEFAULT); 117a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!callbacks) { 118a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown goto cleanup; 119a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 120a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_cb_set(callbacks, NL_CB_VALID, NL_CB_CUSTOM, getaddr_cb, &targ); 121a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, &targ); 122a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 123a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown // sends message and waits for a response 124a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown send_ifaddrmsg(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &ifa, callbacks); 125a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 126a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(targ.foundip) { 127a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown retval = malloc(sizeof(union anyip)); 128a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!retval) { 129a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown logmsg(ANDROID_LOG_FATAL,"getinterface_ip/out of memory"); 130a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown goto cleanup; 131a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 132a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memcpy(retval, &targ.ip, sizeof(union anyip)); 133a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 134a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 135a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drowncleanup: 136a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(callbacks) 137a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_cb_put(callbacks); 138a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 139a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return retval; 140a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 141