blob: ba8052d16fb6cc3b9506626b7bfe91fc4d0cd7e3 [file] [log] [blame]
Daniel Drowna45056e2012-03-23 10:42:54 -05001/*
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 */
Hungming Chen208b2a12021-12-02 18:13:33 +080018#include "getaddr.h"
Daniel Drowna45056e2012-03-23 10:42:54 -050019
Hungming Chen208b2a12021-12-02 18:13:33 +080020#include <errno.h>
Paul Stewartc2f9edd2016-11-11 11:58:52 -080021#include <linux/if_addr.h>
Daniel Drowna45056e2012-03-23 10:42:54 -050022#include <linux/rtnetlink.h>
Hungming Chen208b2a12021-12-02 18:13:33 +080023#include <net/if.h>
24#include <netinet/in.h>
Hungming Chen396b5e72021-12-06 16:58:35 +080025#include <stdlib.h>
Hungming Chen208b2a12021-12-02 18:13:33 +080026#include <string.h>
27#include <strings.h>
28#include <unistd.h>
Daniel Drowna45056e2012-03-23 10:42:54 -050029
Daniel Drowna45056e2012-03-23 10:42:54 -050030#include "logging.h"
31
Hungming Chen208b2a12021-12-02 18:13:33 +080032// Kernel suggests that keep the packet under 8KiB (NLMSG_GOODSIZE) in include/linux/netlink.h.
33#define NLMSG_SIZE 8192
34
35// shared state between getinterface_ip and parse_ifaddrmsg
36// TODO: refactor the communication between getinterface_ip and parse_ifaddrmsg because there
37// is no netlink callback anymore.
Daniel Drowna45056e2012-03-23 10:42:54 -050038struct target {
39 int family;
40 unsigned int ifindex;
41 union anyip ip;
42 int foundip;
43};
44
Hungming Chen208b2a12021-12-02 18:13:33 +080045/* function: parse_ifaddrmsg
46 * parse ifaddrmsg for getinterface_ip
47 * nh - netlink message header
48 * targ_p - (struct target) info for which address we're looking for
49 * and the parsed result if any.
Daniel Drowna45056e2012-03-23 10:42:54 -050050 */
Hungming Chen208b2a12021-12-02 18:13:33 +080051static void parse_ifaddrmsg(struct nlmsghdr *nh, struct target *targ_p) {
Daniel Drowna45056e2012-03-23 10:42:54 -050052 struct ifaddrmsg *ifa_p;
53 struct rtattr *rta_p;
54 int rta_len;
Daniel Drowna45056e2012-03-23 10:42:54 -050055
Hungming Chen208b2a12021-12-02 18:13:33 +080056 ifa_p = (struct ifaddrmsg *)NLMSG_DATA(nh);
Daniel Drowna45056e2012-03-23 10:42:54 -050057 rta_p = (struct rtattr *)IFA_RTA(ifa_p);
58
Hungming Chen208b2a12021-12-02 18:13:33 +080059 if (ifa_p->ifa_index != targ_p->ifindex) return;
Daniel Drowna45056e2012-03-23 10:42:54 -050060
Hungming Chen208b2a12021-12-02 18:13:33 +080061 if (ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) return;
Daniel Drowna45056e2012-03-23 10:42:54 -050062
Hungming Chen208b2a12021-12-02 18:13:33 +080063 rta_len = IFA_PAYLOAD(nh);
Daniel Drowna45056e2012-03-23 10:42:54 -050064 for (; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) {
junyulaic4e591a2018-11-26 22:36:10 +090065 switch (rta_p->rta_type) {
Daniel Drowna45056e2012-03-23 10:42:54 -050066 case IFA_ADDRESS:
junyulaic4e591a2018-11-26 22:36:10 +090067 if ((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) {
Daniel Drowna45056e2012-03-23 10:42:54 -050068 memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
69 targ_p->foundip = 1;
Hungming Chen208b2a12021-12-02 18:13:33 +080070 return;
Daniel Drowna45056e2012-03-23 10:42:54 -050071 }
72 break;
73 case IFA_LOCAL:
junyulaic4e591a2018-11-26 22:36:10 +090074 if (targ_p->family == AF_INET) {
Daniel Drowna45056e2012-03-23 10:42:54 -050075 memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
76 targ_p->foundip = 1;
Hungming Chen208b2a12021-12-02 18:13:33 +080077 return;
Daniel Drowna45056e2012-03-23 10:42:54 -050078 }
79 break;
80 }
81 }
Daniel Drowna45056e2012-03-23 10:42:54 -050082}
83
Hungming Chen208b2a12021-12-02 18:13:33 +080084void sendrecv_ifaddrmsg(struct target *targ_p) {
85 int s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
86 if (s < 0) {
87 logmsg(ANDROID_LOG_ERROR, "open NETLINK_ROUTE socket failed %s", strerror(errno));
88 return;
89 }
90
91 // Fill in netlink structures.
92 struct {
93 struct nlmsghdr n;
94 struct ifaddrmsg r;
95 } req = {
96 // Netlink message header.
97 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
98 .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT,
99 .n.nlmsg_type = RTM_GETADDR,
100
101 // Interface address message header.
102 .r.ifa_family = targ_p->family,
103 };
104
105 // Send interface address message.
106 if ((send(s, &req, req.n.nlmsg_len, 0)) < 0) {
107 logmsg(ANDROID_LOG_ERROR, "send netlink socket failed %s", strerror(errno));
108 close(s);
109 return;
110 }
111
112 // Read interface address message and parse the result if any.
113 ssize_t bytes_read;
114 char buf[NLMSG_SIZE];
115 while ((bytes_read = recv(s, buf, sizeof(buf), 0)) > 0) {
116 struct nlmsghdr *nh = (struct nlmsghdr *)buf;
117 for (; NLMSG_OK(nh, bytes_read); nh = NLMSG_NEXT(nh, bytes_read)) {
118 if (nh->nlmsg_type == NLMSG_DONE) {
119 close(s);
120 return;
121 }
122 if (nh->nlmsg_type == NLMSG_ERROR) {
123 logmsg(ANDROID_LOG_ERROR, "netlink message error");
124 close(s);
125 return;
126 }
127 if (nh->nlmsg_type == RTM_NEWADDR) {
128 // Walk through the all messages and update struct target variable as the deleted
129 // callback behavior of getaddr_cb() which always returns NL_OK.
130 // TODO: review if this can early return once address has been found.
131 parse_ifaddrmsg(nh, targ_p);
132 }
133 }
134 }
135 close(s);
Daniel Drowna45056e2012-03-23 10:42:54 -0500136}
137
138/* function: getinterface_ip
junyulaic4e591a2018-11-26 22:36:10 +0900139 * finds the first global non-privacy IP of the given family for the given interface, or returns
140 * NULL. caller frees pointer
141 * interface - interface to look for
142 * family - family
Daniel Drowna45056e2012-03-23 10:42:54 -0500143 */
144union anyip *getinterface_ip(const char *interface, int family) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500145 union anyip *retval = NULL;
Hungming Chen208b2a12021-12-02 18:13:33 +0800146 struct target targ = {
147 .family = family,
148 .foundip = 0,
149 .ifindex = if_nametoindex(interface),
150 };
Daniel Drowna45056e2012-03-23 10:42:54 -0500151
junyulaic4e591a2018-11-26 22:36:10 +0900152 if (targ.ifindex == 0) {
153 return NULL; // interface not found
Daniel Drowna45056e2012-03-23 10:42:54 -0500154 }
155
Hungming Chen208b2a12021-12-02 18:13:33 +0800156 // sends message and receives the response.
157 sendrecv_ifaddrmsg(&targ);
Daniel Drowna45056e2012-03-23 10:42:54 -0500158
junyulaic4e591a2018-11-26 22:36:10 +0900159 if (targ.foundip) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500160 retval = malloc(sizeof(union anyip));
junyulaic4e591a2018-11-26 22:36:10 +0900161 if (!retval) {
162 logmsg(ANDROID_LOG_FATAL, "getinterface_ip/out of memory");
Hungming Chen208b2a12021-12-02 18:13:33 +0800163 return NULL;
Daniel Drowna45056e2012-03-23 10:42:54 -0500164 }
165 memcpy(retval, &targ.ip, sizeof(union anyip));
166 }
167
Daniel Drowna45056e2012-03-23 10:42:54 -0500168 return retval;
169}