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 23a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <linux/rtnetlink.h> 24a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/handlers.h> 25a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/msg.h> 26a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 27a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "getaddr.h" 28a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "netlink_msg.h" 29a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "logging.h" 30a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 31a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown// shared state between getinterface_ip and getaddr_cb 32a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstruct target { 33a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown int family; 34a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown unsigned int ifindex; 35a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown union anyip ip; 36a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown int foundip; 37a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown}; 38a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 39a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: getaddr_cb 40a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * callback for getinterface_ip 41a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * msg - netlink message 42a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * data - (struct target) info for which address we're looking for 43a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 44a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstatic int getaddr_cb(struct nl_msg *msg, void *data) { 45a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct ifaddrmsg *ifa_p; 46a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct rtattr *rta_p; 47a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown int rta_len; 48a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct target *targ_p = (struct target *)data; 49a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 50a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown ifa_p = (struct ifaddrmsg *)nlmsg_data(nlmsg_hdr(msg)); 51a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown rta_p = (struct rtattr *)IFA_RTA(ifa_p); 52a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 53a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(ifa_p->ifa_index != targ_p->ifindex) 54a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 55a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 56a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) 57a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 58a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 59a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown rta_len = RTM_PAYLOAD(nlmsg_hdr(msg)); 60a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown for (; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) { 61a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown switch(rta_p->rta_type) { 62a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown case IFA_ADDRESS: 63a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) { 64a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr)); 65a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ_p->foundip = 1; 66a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 67a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 68a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown break; 69a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown case IFA_LOCAL: 70a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(targ_p->family == AF_INET) { 71a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr)); 72a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ_p->foundip = 1; 73a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 74a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 75a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown break; 76a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 77a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 78a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 79a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 80a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 81a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 82a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: error_handler 83a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * error callback for getinterface_ip 84a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * nla - source of the error message 85a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * err - netlink message 86a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * arg - (struct target) info for which address we're looking for 87a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 8856ec161d47856212008f47676577882f30853312Lorenzo Colittistatic int error_handler(__attribute__((unused)) struct sockaddr_nl *nla, 8956ec161d47856212008f47676577882f30853312Lorenzo Colitti __attribute__((unused)) struct nlmsgerr *err, 9056ec161d47856212008f47676577882f30853312Lorenzo Colitti __attribute__((unused)) void *arg) { 91a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NL_OK; 92a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 93a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 94a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: getinterface_ip 95a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * finds the first global non-privacy IP of the given family for the given interface, or returns NULL. caller frees pointer 96a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * interface - interface to look for 97a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * family - family 98a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 99a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownunion anyip *getinterface_ip(const char *interface, int family) { 100a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct ifaddrmsg ifa; 101a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct nl_cb *callbacks = NULL; 102a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct target targ; 103a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown union anyip *retval = NULL; 104a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 105a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ.family = family; 106a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ.foundip = 0; 107a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown targ.ifindex = if_nametoindex(interface); 108a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(targ.ifindex == 0) { 109a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NULL; // interface not found 110a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 111a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 112a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memset(&ifa, 0, sizeof(ifa)); 113a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown ifa.ifa_family = targ.family; 114a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 115a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown callbacks = nl_cb_alloc(NL_CB_DEFAULT); 116a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!callbacks) { 117a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown goto cleanup; 118a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 119a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_cb_set(callbacks, NL_CB_VALID, NL_CB_CUSTOM, getaddr_cb, &targ); 120a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, &targ); 121a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 122a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown // sends message and waits for a response 123a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown send_ifaddrmsg(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &ifa, callbacks); 124a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 125a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(targ.foundip) { 126a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown retval = malloc(sizeof(union anyip)); 127a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!retval) { 128a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown logmsg(ANDROID_LOG_FATAL,"getinterface_ip/out of memory"); 129a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown goto cleanup; 130a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 131a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memcpy(retval, &targ.ip, sizeof(union anyip)); 132a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 133a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 134a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drowncleanup: 135a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(callbacks) 136a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_cb_put(callbacks); 137a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 138a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return retval; 139a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 140