blob: f25efc117642c86605cc7571e2929f674799299f [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>
Daniel Drowna45056e2012-03-23 10:42:54 -050025#include <netlink/handlers.h>
26#include <netlink/msg.h>
Hungming Chen208b2a12021-12-02 18:13:33 +080027#include <string.h>
28#include <strings.h>
29#include <unistd.h>
Daniel Drowna45056e2012-03-23 10:42:54 -050030
Daniel Drowna45056e2012-03-23 10:42:54 -050031#include "logging.h"
32
Hungming Chen208b2a12021-12-02 18:13:33 +080033// Kernel suggests that keep the packet under 8KiB (NLMSG_GOODSIZE) in include/linux/netlink.h.
34#define NLMSG_SIZE 8192
35
36// shared state between getinterface_ip and parse_ifaddrmsg
37// TODO: refactor the communication between getinterface_ip and parse_ifaddrmsg because there
38// is no netlink callback anymore.
Daniel Drowna45056e2012-03-23 10:42:54 -050039struct target {
40 int family;
41 unsigned int ifindex;
42 union anyip ip;
43 int foundip;
44};
45
Hungming Chen208b2a12021-12-02 18:13:33 +080046/* function: parse_ifaddrmsg
47 * parse ifaddrmsg for getinterface_ip
48 * nh - netlink message header
49 * targ_p - (struct target) info for which address we're looking for
50 * and the parsed result if any.
Daniel Drowna45056e2012-03-23 10:42:54 -050051 */
Hungming Chen208b2a12021-12-02 18:13:33 +080052static void parse_ifaddrmsg(struct nlmsghdr *nh, struct target *targ_p) {
Daniel Drowna45056e2012-03-23 10:42:54 -050053 struct ifaddrmsg *ifa_p;
54 struct rtattr *rta_p;
55 int rta_len;
Daniel Drowna45056e2012-03-23 10:42:54 -050056
Hungming Chen208b2a12021-12-02 18:13:33 +080057 ifa_p = (struct ifaddrmsg *)NLMSG_DATA(nh);
Daniel Drowna45056e2012-03-23 10:42:54 -050058 rta_p = (struct rtattr *)IFA_RTA(ifa_p);
59
Hungming Chen208b2a12021-12-02 18:13:33 +080060 if (ifa_p->ifa_index != targ_p->ifindex) return;
Daniel Drowna45056e2012-03-23 10:42:54 -050061
Hungming Chen208b2a12021-12-02 18:13:33 +080062 if (ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) return;
Daniel Drowna45056e2012-03-23 10:42:54 -050063
Hungming Chen208b2a12021-12-02 18:13:33 +080064 rta_len = IFA_PAYLOAD(nh);
Daniel Drowna45056e2012-03-23 10:42:54 -050065 for (; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) {
junyulaic4e591a2018-11-26 22:36:10 +090066 switch (rta_p->rta_type) {
Daniel Drowna45056e2012-03-23 10:42:54 -050067 case IFA_ADDRESS:
junyulaic4e591a2018-11-26 22:36:10 +090068 if ((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) {
Daniel Drowna45056e2012-03-23 10:42:54 -050069 memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
70 targ_p->foundip = 1;
Hungming Chen208b2a12021-12-02 18:13:33 +080071 return;
Daniel Drowna45056e2012-03-23 10:42:54 -050072 }
73 break;
74 case IFA_LOCAL:
junyulaic4e591a2018-11-26 22:36:10 +090075 if (targ_p->family == AF_INET) {
Daniel Drowna45056e2012-03-23 10:42:54 -050076 memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
77 targ_p->foundip = 1;
Hungming Chen208b2a12021-12-02 18:13:33 +080078 return;
Daniel Drowna45056e2012-03-23 10:42:54 -050079 }
80 break;
81 }
82 }
Daniel Drowna45056e2012-03-23 10:42:54 -050083}
84
Hungming Chen208b2a12021-12-02 18:13:33 +080085void sendrecv_ifaddrmsg(struct target *targ_p) {
86 int s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
87 if (s < 0) {
88 logmsg(ANDROID_LOG_ERROR, "open NETLINK_ROUTE socket failed %s", strerror(errno));
89 return;
90 }
91
92 // Fill in netlink structures.
93 struct {
94 struct nlmsghdr n;
95 struct ifaddrmsg r;
96 } req = {
97 // Netlink message header.
98 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
99 .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT,
100 .n.nlmsg_type = RTM_GETADDR,
101
102 // Interface address message header.
103 .r.ifa_family = targ_p->family,
104 };
105
106 // Send interface address message.
107 if ((send(s, &req, req.n.nlmsg_len, 0)) < 0) {
108 logmsg(ANDROID_LOG_ERROR, "send netlink socket failed %s", strerror(errno));
109 close(s);
110 return;
111 }
112
113 // Read interface address message and parse the result if any.
114 ssize_t bytes_read;
115 char buf[NLMSG_SIZE];
116 while ((bytes_read = recv(s, buf, sizeof(buf), 0)) > 0) {
117 struct nlmsghdr *nh = (struct nlmsghdr *)buf;
118 for (; NLMSG_OK(nh, bytes_read); nh = NLMSG_NEXT(nh, bytes_read)) {
119 if (nh->nlmsg_type == NLMSG_DONE) {
120 close(s);
121 return;
122 }
123 if (nh->nlmsg_type == NLMSG_ERROR) {
124 logmsg(ANDROID_LOG_ERROR, "netlink message error");
125 close(s);
126 return;
127 }
128 if (nh->nlmsg_type == RTM_NEWADDR) {
129 // Walk through the all messages and update struct target variable as the deleted
130 // callback behavior of getaddr_cb() which always returns NL_OK.
131 // TODO: review if this can early return once address has been found.
132 parse_ifaddrmsg(nh, targ_p);
133 }
134 }
135 }
136 close(s);
Daniel Drowna45056e2012-03-23 10:42:54 -0500137}
138
139/* function: getinterface_ip
junyulaic4e591a2018-11-26 22:36:10 +0900140 * finds the first global non-privacy IP of the given family for the given interface, or returns
141 * NULL. caller frees pointer
142 * interface - interface to look for
143 * family - family
Daniel Drowna45056e2012-03-23 10:42:54 -0500144 */
145union anyip *getinterface_ip(const char *interface, int family) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500146 union anyip *retval = NULL;
Hungming Chen208b2a12021-12-02 18:13:33 +0800147 struct target targ = {
148 .family = family,
149 .foundip = 0,
150 .ifindex = if_nametoindex(interface),
151 };
Daniel Drowna45056e2012-03-23 10:42:54 -0500152
junyulaic4e591a2018-11-26 22:36:10 +0900153 if (targ.ifindex == 0) {
154 return NULL; // interface not found
Daniel Drowna45056e2012-03-23 10:42:54 -0500155 }
156
Hungming Chen208b2a12021-12-02 18:13:33 +0800157 // sends message and receives the response.
158 sendrecv_ifaddrmsg(&targ);
Daniel Drowna45056e2012-03-23 10:42:54 -0500159
junyulaic4e591a2018-11-26 22:36:10 +0900160 if (targ.foundip) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500161 retval = malloc(sizeof(union anyip));
junyulaic4e591a2018-11-26 22:36:10 +0900162 if (!retval) {
163 logmsg(ANDROID_LOG_FATAL, "getinterface_ip/out of memory");
Hungming Chen208b2a12021-12-02 18:13:33 +0800164 return NULL;
Daniel Drowna45056e2012-03-23 10:42:54 -0500165 }
166 memcpy(retval, &targ.ip, sizeof(union anyip));
167 }
168
Daniel Drowna45056e2012-03-23 10:42:54 -0500169 return retval;
170}