xref: /aosp_15_r20/system/netd/server/NetlinkManager.cpp (revision 8542734a0dd1db395a4d42aae09c37f3c3c3e7a1)
1*8542734aSAndroid Build Coastguard Worker /*
2*8542734aSAndroid Build Coastguard Worker  * Copyright (C) 2008 The Android Open Source Project
3*8542734aSAndroid Build Coastguard Worker  *
4*8542734aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*8542734aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*8542734aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*8542734aSAndroid Build Coastguard Worker  *
8*8542734aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*8542734aSAndroid Build Coastguard Worker  *
10*8542734aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*8542734aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*8542734aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8542734aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*8542734aSAndroid Build Coastguard Worker  * limitations under the License.
15*8542734aSAndroid Build Coastguard Worker  */
16*8542734aSAndroid Build Coastguard Worker 
17*8542734aSAndroid Build Coastguard Worker #include <errno.h>
18*8542734aSAndroid Build Coastguard Worker #include <stdio.h>
19*8542734aSAndroid Build Coastguard Worker #include <string.h>
20*8542734aSAndroid Build Coastguard Worker #include <unistd.h>
21*8542734aSAndroid Build Coastguard Worker 
22*8542734aSAndroid Build Coastguard Worker #include <sys/socket.h>
23*8542734aSAndroid Build Coastguard Worker #include <sys/time.h>
24*8542734aSAndroid Build Coastguard Worker #include <sys/types.h>
25*8542734aSAndroid Build Coastguard Worker #include <sys/un.h>
26*8542734aSAndroid Build Coastguard Worker 
27*8542734aSAndroid Build Coastguard Worker #include <linux/netlink.h>
28*8542734aSAndroid Build Coastguard Worker #include <linux/rtnetlink.h>
29*8542734aSAndroid Build Coastguard Worker 
30*8542734aSAndroid Build Coastguard Worker #define LOG_TAG "Netd"
31*8542734aSAndroid Build Coastguard Worker 
32*8542734aSAndroid Build Coastguard Worker #include <log/log.h>
33*8542734aSAndroid Build Coastguard Worker 
34*8542734aSAndroid Build Coastguard Worker #include <linux/netfilter/nfnetlink.h>
35*8542734aSAndroid Build Coastguard Worker #include <linux/netfilter/nfnetlink_log.h>
36*8542734aSAndroid Build Coastguard Worker #include <linux/netfilter/nfnetlink_compat.h>
37*8542734aSAndroid Build Coastguard Worker 
38*8542734aSAndroid Build Coastguard Worker #include <arpa/inet.h>
39*8542734aSAndroid Build Coastguard Worker 
40*8542734aSAndroid Build Coastguard Worker #include "NetlinkManager.h"
41*8542734aSAndroid Build Coastguard Worker #include "NetlinkHandler.h"
42*8542734aSAndroid Build Coastguard Worker 
43*8542734aSAndroid Build Coastguard Worker #include "pcap-netfilter-linux-android.h"
44*8542734aSAndroid Build Coastguard Worker 
45*8542734aSAndroid Build Coastguard Worker namespace android {
46*8542734aSAndroid Build Coastguard Worker namespace net {
47*8542734aSAndroid Build Coastguard Worker 
48*8542734aSAndroid Build Coastguard Worker const int NetlinkManager::NFLOG_QUOTA_GROUP = 1;
49*8542734aSAndroid Build Coastguard Worker const int NetlinkManager::NETFILTER_STRICT_GROUP = 2;
50*8542734aSAndroid Build Coastguard Worker const int NetlinkManager::NFLOG_WAKEUP_GROUP = 3;
51*8542734aSAndroid Build Coastguard Worker 
52*8542734aSAndroid Build Coastguard Worker NetlinkManager *NetlinkManager::sInstance = nullptr;
53*8542734aSAndroid Build Coastguard Worker 
Instance()54*8542734aSAndroid Build Coastguard Worker NetlinkManager *NetlinkManager::Instance() {
55*8542734aSAndroid Build Coastguard Worker     if (!sInstance)
56*8542734aSAndroid Build Coastguard Worker         sInstance = new NetlinkManager();
57*8542734aSAndroid Build Coastguard Worker     return sInstance;
58*8542734aSAndroid Build Coastguard Worker }
59*8542734aSAndroid Build Coastguard Worker 
NetlinkManager()60*8542734aSAndroid Build Coastguard Worker NetlinkManager::NetlinkManager() {
61*8542734aSAndroid Build Coastguard Worker     mBroadcaster = nullptr;
62*8542734aSAndroid Build Coastguard Worker }
63*8542734aSAndroid Build Coastguard Worker 
~NetlinkManager()64*8542734aSAndroid Build Coastguard Worker NetlinkManager::~NetlinkManager() {
65*8542734aSAndroid Build Coastguard Worker }
66*8542734aSAndroid Build Coastguard Worker 
setupSocket(int * sock,int netlinkFamily,int groups,int format,bool configNflog)67*8542734aSAndroid Build Coastguard Worker NetlinkHandler *NetlinkManager::setupSocket(int *sock, int netlinkFamily,
68*8542734aSAndroid Build Coastguard Worker     int groups, int format, bool configNflog) {
69*8542734aSAndroid Build Coastguard Worker 
70*8542734aSAndroid Build Coastguard Worker     struct sockaddr_nl nladdr;
71*8542734aSAndroid Build Coastguard Worker     int sz = 64 * 1024;
72*8542734aSAndroid Build Coastguard Worker     int on = 1;
73*8542734aSAndroid Build Coastguard Worker 
74*8542734aSAndroid Build Coastguard Worker     memset(&nladdr, 0, sizeof(nladdr));
75*8542734aSAndroid Build Coastguard Worker     nladdr.nl_family = AF_NETLINK;
76*8542734aSAndroid Build Coastguard Worker     // Kernel will assign a unique nl_pid if set to zero.
77*8542734aSAndroid Build Coastguard Worker     nladdr.nl_pid = 0;
78*8542734aSAndroid Build Coastguard Worker     nladdr.nl_groups = groups;
79*8542734aSAndroid Build Coastguard Worker 
80*8542734aSAndroid Build Coastguard Worker     if ((*sock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, netlinkFamily)) < 0) {
81*8542734aSAndroid Build Coastguard Worker         ALOGE("Unable to create netlink socket for family %d: %s", netlinkFamily, strerror(errno));
82*8542734aSAndroid Build Coastguard Worker         return nullptr;
83*8542734aSAndroid Build Coastguard Worker     }
84*8542734aSAndroid Build Coastguard Worker 
85*8542734aSAndroid Build Coastguard Worker     // When running in a net/user namespace, SO_RCVBUFFORCE will fail because
86*8542734aSAndroid Build Coastguard Worker     // it will check for the CAP_NET_ADMIN capability in the root namespace.
87*8542734aSAndroid Build Coastguard Worker     // Try using SO_RCVBUF if that fails.
88*8542734aSAndroid Build Coastguard Worker     if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0 &&
89*8542734aSAndroid Build Coastguard Worker         setsockopt(*sock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) {
90*8542734aSAndroid Build Coastguard Worker         ALOGE("Unable to set uevent socket SO_RCVBUF option: %s", strerror(errno));
91*8542734aSAndroid Build Coastguard Worker         close(*sock);
92*8542734aSAndroid Build Coastguard Worker         return nullptr;
93*8542734aSAndroid Build Coastguard Worker     }
94*8542734aSAndroid Build Coastguard Worker 
95*8542734aSAndroid Build Coastguard Worker     if (setsockopt(*sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
96*8542734aSAndroid Build Coastguard Worker         SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
97*8542734aSAndroid Build Coastguard Worker         close(*sock);
98*8542734aSAndroid Build Coastguard Worker         return nullptr;
99*8542734aSAndroid Build Coastguard Worker     }
100*8542734aSAndroid Build Coastguard Worker 
101*8542734aSAndroid Build Coastguard Worker     if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
102*8542734aSAndroid Build Coastguard Worker         ALOGE("Unable to bind netlink socket: %s", strerror(errno));
103*8542734aSAndroid Build Coastguard Worker         close(*sock);
104*8542734aSAndroid Build Coastguard Worker         return nullptr;
105*8542734aSAndroid Build Coastguard Worker     }
106*8542734aSAndroid Build Coastguard Worker 
107*8542734aSAndroid Build Coastguard Worker     if (configNflog) {
108*8542734aSAndroid Build Coastguard Worker         if (android_nflog_send_config_cmd(*sock, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) {
109*8542734aSAndroid Build Coastguard Worker             ALOGE("Failed NFULNL_CFG_CMD_PF_UNBIND: %s", strerror(errno));
110*8542734aSAndroid Build Coastguard Worker             return nullptr;
111*8542734aSAndroid Build Coastguard Worker         }
112*8542734aSAndroid Build Coastguard Worker         if (android_nflog_send_config_cmd(*sock, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) {
113*8542734aSAndroid Build Coastguard Worker             ALOGE("Failed NFULNL_CFG_CMD_PF_BIND: %s", strerror(errno));
114*8542734aSAndroid Build Coastguard Worker             return nullptr;
115*8542734aSAndroid Build Coastguard Worker         }
116*8542734aSAndroid Build Coastguard Worker         if (android_nflog_send_config_cmd(*sock, 0, NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
117*8542734aSAndroid Build Coastguard Worker             ALOGE("Failed NFULNL_CFG_CMD_BIND: %s", strerror(errno));
118*8542734aSAndroid Build Coastguard Worker             return nullptr;
119*8542734aSAndroid Build Coastguard Worker         }
120*8542734aSAndroid Build Coastguard Worker     }
121*8542734aSAndroid Build Coastguard Worker 
122*8542734aSAndroid Build Coastguard Worker     NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
123*8542734aSAndroid Build Coastguard Worker     if (handler->start()) {
124*8542734aSAndroid Build Coastguard Worker         ALOGE("Unable to start NetlinkHandler: %s", strerror(errno));
125*8542734aSAndroid Build Coastguard Worker         close(*sock);
126*8542734aSAndroid Build Coastguard Worker         return nullptr;
127*8542734aSAndroid Build Coastguard Worker     }
128*8542734aSAndroid Build Coastguard Worker 
129*8542734aSAndroid Build Coastguard Worker     return handler;
130*8542734aSAndroid Build Coastguard Worker }
131*8542734aSAndroid Build Coastguard Worker 
start()132*8542734aSAndroid Build Coastguard Worker int NetlinkManager::start() {
133*8542734aSAndroid Build Coastguard Worker     if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
134*8542734aSAndroid Build Coastguard Worker          0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII, false)) == nullptr) {
135*8542734aSAndroid Build Coastguard Worker         return -1;
136*8542734aSAndroid Build Coastguard Worker     }
137*8542734aSAndroid Build Coastguard Worker 
138*8542734aSAndroid Build Coastguard Worker     if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE,
139*8542734aSAndroid Build Coastguard Worker                                      RTMGRP_LINK |
140*8542734aSAndroid Build Coastguard Worker                                      RTMGRP_IPV4_IFADDR |
141*8542734aSAndroid Build Coastguard Worker                                      RTMGRP_IPV6_IFADDR |
142*8542734aSAndroid Build Coastguard Worker                                      RTMGRP_IPV6_ROUTE |
143*8542734aSAndroid Build Coastguard Worker                                      (1 << (RTNLGRP_ND_USEROPT - 1)),
144*8542734aSAndroid Build Coastguard Worker          NetlinkListener::NETLINK_FORMAT_BINARY, false)) == nullptr) {
145*8542734aSAndroid Build Coastguard Worker         return -1;
146*8542734aSAndroid Build Coastguard Worker     }
147*8542734aSAndroid Build Coastguard Worker 
148*8542734aSAndroid Build Coastguard Worker     if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,
149*8542734aSAndroid Build Coastguard Worker             NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY, false)) == nullptr) {
150*8542734aSAndroid Build Coastguard Worker         ALOGW("Unable to open qlog quota socket, check if xt_quota2 can send via UeventHandler");
151*8542734aSAndroid Build Coastguard Worker         // TODO: return -1 once the emulator gets a new kernel.
152*8542734aSAndroid Build Coastguard Worker     }
153*8542734aSAndroid Build Coastguard Worker 
154*8542734aSAndroid Build Coastguard Worker     if ((mStrictHandler = setupSocket(&mStrictSock, NETLINK_NETFILTER,
155*8542734aSAndroid Build Coastguard Worker             0, NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST, true)) == nullptr) {
156*8542734aSAndroid Build Coastguard Worker         ALOGE("Unable to open strict socket");
157*8542734aSAndroid Build Coastguard Worker         // TODO: return -1 once the emulator gets a new kernel.
158*8542734aSAndroid Build Coastguard Worker     }
159*8542734aSAndroid Build Coastguard Worker 
160*8542734aSAndroid Build Coastguard Worker     return 0;
161*8542734aSAndroid Build Coastguard Worker }
162*8542734aSAndroid Build Coastguard Worker 
stop()163*8542734aSAndroid Build Coastguard Worker int NetlinkManager::stop() {
164*8542734aSAndroid Build Coastguard Worker     int status = 0;
165*8542734aSAndroid Build Coastguard Worker 
166*8542734aSAndroid Build Coastguard Worker     if (mUeventHandler->stop()) {
167*8542734aSAndroid Build Coastguard Worker         ALOGE("Unable to stop uevent NetlinkHandler: %s", strerror(errno));
168*8542734aSAndroid Build Coastguard Worker         status = -1;
169*8542734aSAndroid Build Coastguard Worker     }
170*8542734aSAndroid Build Coastguard Worker 
171*8542734aSAndroid Build Coastguard Worker     delete mUeventHandler;
172*8542734aSAndroid Build Coastguard Worker     mUeventHandler = nullptr;
173*8542734aSAndroid Build Coastguard Worker 
174*8542734aSAndroid Build Coastguard Worker     close(mUeventSock);
175*8542734aSAndroid Build Coastguard Worker     mUeventSock = -1;
176*8542734aSAndroid Build Coastguard Worker 
177*8542734aSAndroid Build Coastguard Worker     if (mRouteHandler->stop()) {
178*8542734aSAndroid Build Coastguard Worker         ALOGE("Unable to stop route NetlinkHandler: %s", strerror(errno));
179*8542734aSAndroid Build Coastguard Worker         status = -1;
180*8542734aSAndroid Build Coastguard Worker     }
181*8542734aSAndroid Build Coastguard Worker 
182*8542734aSAndroid Build Coastguard Worker     delete mRouteHandler;
183*8542734aSAndroid Build Coastguard Worker     mRouteHandler = nullptr;
184*8542734aSAndroid Build Coastguard Worker 
185*8542734aSAndroid Build Coastguard Worker     close(mRouteSock);
186*8542734aSAndroid Build Coastguard Worker     mRouteSock = -1;
187*8542734aSAndroid Build Coastguard Worker 
188*8542734aSAndroid Build Coastguard Worker     if (mQuotaHandler) {
189*8542734aSAndroid Build Coastguard Worker         if (mQuotaHandler->stop()) {
190*8542734aSAndroid Build Coastguard Worker             ALOGE("Unable to stop quota NetlinkHandler: %s", strerror(errno));
191*8542734aSAndroid Build Coastguard Worker             status = -1;
192*8542734aSAndroid Build Coastguard Worker         }
193*8542734aSAndroid Build Coastguard Worker 
194*8542734aSAndroid Build Coastguard Worker         delete mQuotaHandler;
195*8542734aSAndroid Build Coastguard Worker         mQuotaHandler = nullptr;
196*8542734aSAndroid Build Coastguard Worker 
197*8542734aSAndroid Build Coastguard Worker         close(mQuotaSock);
198*8542734aSAndroid Build Coastguard Worker         mQuotaSock = -1;
199*8542734aSAndroid Build Coastguard Worker     }
200*8542734aSAndroid Build Coastguard Worker 
201*8542734aSAndroid Build Coastguard Worker     if (mStrictHandler) {
202*8542734aSAndroid Build Coastguard Worker         if (mStrictHandler->stop()) {
203*8542734aSAndroid Build Coastguard Worker             ALOGE("Unable to stop strict NetlinkHandler: %s", strerror(errno));
204*8542734aSAndroid Build Coastguard Worker             status = -1;
205*8542734aSAndroid Build Coastguard Worker         }
206*8542734aSAndroid Build Coastguard Worker 
207*8542734aSAndroid Build Coastguard Worker         delete mStrictHandler;
208*8542734aSAndroid Build Coastguard Worker         mStrictHandler = nullptr;
209*8542734aSAndroid Build Coastguard Worker 
210*8542734aSAndroid Build Coastguard Worker         close(mStrictSock);
211*8542734aSAndroid Build Coastguard Worker         mStrictSock = -1;
212*8542734aSAndroid Build Coastguard Worker     }
213*8542734aSAndroid Build Coastguard Worker 
214*8542734aSAndroid Build Coastguard Worker     return status;
215*8542734aSAndroid Build Coastguard Worker }
216*8542734aSAndroid Build Coastguard Worker 
217*8542734aSAndroid Build Coastguard Worker }  // namespace net
218*8542734aSAndroid Build Coastguard Worker }  // namespace android
219