blob: 7936c7db5cb035dcbccfd3bd5ea84b8e35c7a226 [file] [log] [blame]
Maciej Żenczykowskib70da762019-01-28 15:20:48 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
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
17#include "ClatUtils.h"
18
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080019#include <errno.h>
20#include <linux/if.h>
Maciej Żenczykowski7330b022019-01-28 17:30:24 -080021#include <linux/netlink.h>
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080022#include <sys/ioctl.h>
23#include <sys/socket.h>
24#include <sys/types.h>
25#include <unistd.h>
26
Maciej Żenczykowskib70da762019-01-28 15:20:48 -080027#define LOG_TAG "ClatUtils"
28#include <log/log.h>
29
Maciej Żenczykowski7330b022019-01-28 17:30:24 -080030#include "NetlinkCommands.h"
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080031#include "android-base/unique_fd.h"
Maciej Żenczykowski88d28ff2019-03-25 11:54:32 -070032#include "bpf/BpfUtils.h"
33#include "netdbpf/bpf_shared.h"
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080034
Maciej Żenczykowskib70da762019-01-28 15:20:48 -080035namespace android {
36namespace net {
37
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080038int hardwareAddressType(const std::string& interface) {
39 base::unique_fd ufd(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
40
41 if (ufd < 0) {
42 const int err = errno;
43 ALOGE("socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)");
44 return -err;
45 };
46
47 struct ifreq ifr = {};
48 // We use strncpy() instead of strlcpy() since kernel has to be able
49 // to handle non-zero terminated junk passed in by userspace anyway,
50 // and this way too long interface names (more than IFNAMSIZ-1 = 15
51 // characters plus terminating NULL) will not get truncated to 15
52 // characters and zero-terminated and thus potentially erroneously
53 // match a truncated interface if one were to exist.
54 strncpy(ifr.ifr_name, interface.c_str(), sizeof(ifr.ifr_name));
55
56 if (ioctl(ufd, SIOCGIFHWADDR, &ifr, sizeof(ifr))) return -errno;
57
58 return ifr.ifr_hwaddr.sa_family;
59}
60
Maciej Żenczykowski88d28ff2019-03-25 11:54:32 -070061int getClatMapFd(void) {
62 const int fd = bpf::bpfFdGet(CLAT_MAP_PATH, 0);
63 return (fd == -1) ? -errno : fd;
64}
65
Maciej Żenczykowski949d84a2019-01-28 17:22:30 -080066int getClatProgFd(bool with_ethernet_header) {
67 const int fd =
68 bpf::bpfFdGet(with_ethernet_header ? CLAT_PROG_ETHER_PATH : CLAT_PROG_RAWIP_PATH, 0);
69 return (fd == -1) ? -errno : fd;
70}
71
Maciej Żenczykowski7330b022019-01-28 17:30:24 -080072// TODO: use //system/netd/server/NetlinkCommands.cpp:openNetlinkSocket(protocol)
73int openNetlinkSocket(void) {
74 base::unique_fd fd(socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE));
75 if (fd == -1) {
76 const int err = errno;
77 ALOGE("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)");
78 return -err;
79 }
80
81 int rv;
82
83 const int on = 1;
84 rv = setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on));
85 if (rv) ALOGE("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, %d)", on);
86
87 // this is needed to get sane strace netlink parsing, it allocates the pid
88 rv = bind(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR));
89 if (rv) {
90 const int err = errno;
91 ALOGE("bind(fd, {AF_NETLINK, 0, 0})");
92 return -err;
93 }
94
95 // we do not want to receive messages from anyone besides the kernel
96 rv = connect(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR));
97 if (rv) {
98 const int err = errno;
99 ALOGE("connect(fd, {AF_NETLINK, 0, 0})");
100 return -err;
101 }
102
103 return fd.release();
104}
105
Maciej Żenczykowski992a51d2019-02-11 18:06:56 -0800106// TODO: merge with //system/netd/server/SockDiag.cpp:checkError(fd)
107int processNetlinkResponse(int fd) {
108 struct {
109 nlmsghdr h;
110 nlmsgerr e;
111 char buf[256];
112 } resp = {};
113
114 const int rv = recv(fd, &resp, sizeof(resp), MSG_TRUNC);
115
116 if (rv == -1) {
117 const int err = errno;
118 ALOGE("recv() failed");
119 return -err;
120 }
121
122 if (rv < (int)NLMSG_SPACE(sizeof(struct nlmsgerr))) {
123 ALOGE("recv() returned short packet: %d", rv);
124 return -EMSGSIZE;
125 }
126
127 if (resp.h.nlmsg_len != (unsigned)rv) {
128 ALOGE("recv() returned invalid header length: %d != %d", resp.h.nlmsg_len, rv);
129 return -EBADMSG;
130 }
131
132 if (resp.h.nlmsg_type != NLMSG_ERROR) {
133 ALOGE("recv() did not return NLMSG_ERROR message: %d", resp.h.nlmsg_type);
134 return -EBADMSG;
135 }
136
137 return resp.e.error; // returns 0 on success
138}
139
Maciej Żenczykowskib70da762019-01-28 15:20:48 -0800140} // namespace net
141} // namespace android