You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.9 KiB
139 lines
3.9 KiB
4 months ago
|
/*
|
||
|
* Copyright 2012 Daniel Drown
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* getaddr.c - get a locally configured address
|
||
|
*/
|
||
|
#include <net/if.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <string.h>
|
||
|
#include <strings.h>
|
||
|
|
||
|
#include <linux/if_addr.h>
|
||
|
#include <linux/rtnetlink.h>
|
||
|
#include <netlink/handlers.h>
|
||
|
#include <netlink/msg.h>
|
||
|
|
||
|
#include "getaddr.h"
|
||
|
#include "logging.h"
|
||
|
#include "netlink_msg.h"
|
||
|
|
||
|
// shared state between getinterface_ip and getaddr_cb
|
||
|
struct target {
|
||
|
int family;
|
||
|
unsigned int ifindex;
|
||
|
union anyip ip;
|
||
|
int foundip;
|
||
|
};
|
||
|
|
||
|
/* function: getaddr_cb
|
||
|
* callback for getinterface_ip
|
||
|
* msg - netlink message
|
||
|
* data - (struct target) info for which address we're looking for
|
||
|
*/
|
||
|
static int getaddr_cb(struct nl_msg *msg, void *data) {
|
||
|
struct ifaddrmsg *ifa_p;
|
||
|
struct rtattr *rta_p;
|
||
|
int rta_len;
|
||
|
struct target *targ_p = (struct target *)data;
|
||
|
|
||
|
ifa_p = (struct ifaddrmsg *)nlmsg_data(nlmsg_hdr(msg));
|
||
|
rta_p = (struct rtattr *)IFA_RTA(ifa_p);
|
||
|
|
||
|
if (ifa_p->ifa_index != targ_p->ifindex) return NL_OK;
|
||
|
|
||
|
if (ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) return NL_OK;
|
||
|
|
||
|
rta_len = RTM_PAYLOAD(nlmsg_hdr(msg));
|
||
|
for (; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) {
|
||
|
switch (rta_p->rta_type) {
|
||
|
case IFA_ADDRESS:
|
||
|
if ((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) {
|
||
|
memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
|
||
|
targ_p->foundip = 1;
|
||
|
return NL_OK;
|
||
|
}
|
||
|
break;
|
||
|
case IFA_LOCAL:
|
||
|
if (targ_p->family == AF_INET) {
|
||
|
memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
|
||
|
targ_p->foundip = 1;
|
||
|
return NL_OK;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NL_OK;
|
||
|
}
|
||
|
|
||
|
/* function: error_handler
|
||
|
* error callback for getinterface_ip
|
||
|
* nla - source of the error message
|
||
|
* err - netlink message
|
||
|
* arg - (struct target) info for which address we're looking for
|
||
|
*/
|
||
|
static int error_handler(__attribute__((unused)) struct sockaddr_nl *nla,
|
||
|
__attribute__((unused)) struct nlmsgerr *err,
|
||
|
__attribute__((unused)) void *arg) {
|
||
|
return NL_OK;
|
||
|
}
|
||
|
|
||
|
/* function: getinterface_ip
|
||
|
* finds the first global non-privacy IP of the given family for the given interface, or returns
|
||
|
* NULL. caller frees pointer
|
||
|
* interface - interface to look for
|
||
|
* family - family
|
||
|
*/
|
||
|
union anyip *getinterface_ip(const char *interface, int family) {
|
||
|
struct ifaddrmsg ifa;
|
||
|
struct nl_cb *callbacks = NULL;
|
||
|
struct target targ;
|
||
|
union anyip *retval = NULL;
|
||
|
|
||
|
targ.family = family;
|
||
|
targ.foundip = 0;
|
||
|
targ.ifindex = if_nametoindex(interface);
|
||
|
if (targ.ifindex == 0) {
|
||
|
return NULL; // interface not found
|
||
|
}
|
||
|
|
||
|
memset(&ifa, 0, sizeof(ifa));
|
||
|
ifa.ifa_family = targ.family;
|
||
|
|
||
|
callbacks = nl_cb_alloc(NL_CB_DEFAULT);
|
||
|
if (!callbacks) {
|
||
|
goto cleanup;
|
||
|
}
|
||
|
nl_cb_set(callbacks, NL_CB_VALID, NL_CB_CUSTOM, getaddr_cb, &targ);
|
||
|
nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, &targ);
|
||
|
|
||
|
// sends message and waits for a response
|
||
|
send_ifaddrmsg(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &ifa, callbacks);
|
||
|
|
||
|
if (targ.foundip) {
|
||
|
retval = malloc(sizeof(union anyip));
|
||
|
if (!retval) {
|
||
|
logmsg(ANDROID_LOG_FATAL, "getinterface_ip/out of memory");
|
||
|
goto cleanup;
|
||
|
}
|
||
|
memcpy(retval, &targ.ip, sizeof(union anyip));
|
||
|
}
|
||
|
|
||
|
cleanup:
|
||
|
if (callbacks) nl_cb_put(callbacks);
|
||
|
|
||
|
return retval;
|
||
|
}
|