VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/mkrawsock.c@ 94701

Last change on this file since 94701 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.2 KB
Line 
1/* $Id: mkrawsock.c 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * Auxiliary server to create raw-sockets when debugging unprivileged.
4 */
5
6/*
7 * Copyright (C) 2013-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef __linux__
19#define _GNU_SOURCE
20#endif
21
22#ifdef __sun__
23#if __STDC_VERSION__ - 0 >= 199901L
24#define _XOPEN_SOURCE 600
25#else
26#define _XOPEN_SOURCE 500
27#endif
28#define __EXTENSIONS__ 1
29#endif
30
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <sys/socket.h>
34#include <sys/un.h>
35#include <netinet/in.h>
36#ifdef __linux__
37#include <linux/icmp.h> /* for ICMP_FILTER */
38#endif
39#include <errno.h>
40#include <fcntl.h>
41#include <pwd.h>
42#include <signal.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47
48
49static void handler(int sig);
50static void serve(int s);
51static int mkrawsock(int family);
52
53volatile sig_atomic_t signaled = 0;
54
55int
56main(int argc, char **argv)
57{
58 struct sigaction sa;
59 struct sockaddr_un sux; /* because solaris */
60 struct passwd *pw;
61 size_t pathlen;
62 char *slash;
63 int s, client;
64 int status;
65
66 memset(&sux, 0, sizeof(sux));
67 sux.sun_family = AF_UNIX;
68
69 if (getuid() == 0) {
70 if (argc != 2) {
71 fprintf(stderr, "username required when run as root\n");
72 return EXIT_FAILURE;
73 }
74
75 errno = 0;
76 pw = getpwnam(argv[1]);
77 if (pw == NULL) {
78 perror("getpwnam");
79 return EXIT_FAILURE;
80 }
81 if (pw->pw_uid == 0) {
82 fprintf(stderr, "%s is superuser\n", pw->pw_name);
83 return EXIT_FAILURE;
84 }
85 }
86 else {
87 errno = 0;
88 pw = getpwuid(getuid());
89 if (pw == NULL) {
90 perror("getpwuid");
91 return EXIT_FAILURE;
92 }
93 }
94
95 pathlen = snprintf(sux.sun_path, sizeof(sux.sun_path),
96 "/tmp/.vbox-%s-aux/mkrawsock", pw->pw_name);
97 if (pathlen > sizeof(sux.sun_path)) {
98 fprintf(stderr, "socket pathname truncated\n");
99 return EXIT_FAILURE;
100 }
101
102 slash = strrchr(sux.sun_path, '/');
103 if (slash == NULL) {
104 fprintf(stderr, "%s: no directory separator\n", sux.sun_path);
105 return EXIT_FAILURE;
106 }
107
108 *slash = '\0';
109
110 status = mkdir(sux.sun_path, 0700);
111 if (status == 0) {
112 status = chown(sux.sun_path, pw->pw_uid, pw->pw_gid);
113 if (status < 0) {
114 perror("chown");
115 return EXIT_FAILURE;
116 }
117 }
118 else if (errno != EEXIST) {
119 perror("mkdir");
120 return EXIT_FAILURE;
121 }
122 else {
123 int dirfd;
124 struct stat st;
125
126 dirfd = open(sux.sun_path, O_RDONLY, O_DIRECTORY);
127 if (dirfd < 0) {
128 perror(sux.sun_path);
129 return EXIT_FAILURE;
130 }
131
132 status = fstat(dirfd, &st);
133 close(dirfd);
134
135 if (status < 0) {
136 perror(sux.sun_path);
137 return EXIT_FAILURE;
138 }
139
140 if (st.st_uid != pw->pw_uid) {
141 fprintf(stderr, "%s: exists but not owned by %s\n",
142 sux.sun_path, pw->pw_name);
143 return EXIT_FAILURE;
144 }
145
146 if ((st.st_mode & 0777) != 0700) {
147 fprintf(stderr, "%s: bad mode %04o\n",
148 sux.sun_path, (unsigned int)(st.st_mode & 0777));
149 return EXIT_FAILURE;
150 }
151 }
152
153 *slash = '/';
154
155#if 0
156 status = unlink(sux.sun_path);
157 if (status < 0 && errno != ENOENT) {
158 perror("unlink");
159 }
160#endif
161
162 s = socket(PF_UNIX, SOCK_STREAM, 0);
163 if (s < 0) {
164 perror("socket");
165 return EXIT_FAILURE;
166 }
167
168 status = bind(s, (struct sockaddr *)&sux,
169 (sizeof(sux) - sizeof(sux.sun_path)
170 + strlen(sux.sun_path) + 1));
171 if (status < 0) {
172 perror(sux.sun_path);
173 close(s);
174 return EXIT_FAILURE;
175 }
176
177 status = chown(sux.sun_path, pw->pw_uid, pw->pw_gid);
178 if (status < 0) {
179 perror("chown");
180 close(s);
181 return EXIT_FAILURE;
182 }
183
184 status = chmod(sux.sun_path, 0600);
185 if (status < 0) {
186 perror("chmod");
187 close(s);
188 return EXIT_FAILURE;
189 }
190
191 status = listen(s, 1);
192 if (status < 0) {
193 perror("listen");
194 close(s);
195 return EXIT_FAILURE;
196 }
197
198 memset(&sa, 0, sizeof(sa));
199 sa.sa_handler = handler;
200 sigemptyset(&sa.sa_mask);
201
202 sigaction(SIGINT, &sa, NULL);
203 sigaction(SIGTERM, &sa, NULL);
204
205 while (!signaled) {
206 client = accept(s, NULL, 0);
207 if (client < 0) {
208 perror("accept");
209 continue;
210 }
211
212 serve(client);
213 close(client);
214 }
215
216 close(s);
217 status = unlink(sux.sun_path);
218 if (status < 0) {
219 perror("unlink");
220 }
221
222 return EXIT_SUCCESS;
223}
224
225
226static void
227handler(int sig)
228{
229 signaled = 1;
230}
231
232
233static void
234serve(int client)
235{
236#ifdef SO_PEERCRED
237 struct ucred cr;
238 socklen_t crlen;
239#endif
240 ssize_t nread, nsent;
241 struct msghdr mh;
242 struct iovec iov[1];
243 char buf[1];
244 struct cmsghdr *cmh;
245 char cmsg[CMSG_SPACE(sizeof(int))];
246 int fd;
247 int status;
248
249#ifdef SO_PEERCRED
250 crlen = sizeof(cr);
251 status = getsockopt(client, SOL_SOCKET, SO_PEERCRED, &cr, &crlen);
252 if (status < 0) {
253 perror("SO_PEERCRED");
254 return;
255 }
256
257 fprintf(stderr, "request from pid %lu uid %lu ",
258 (unsigned long)cr.pid, (unsigned long)cr.uid);
259#endif
260
261 nread = read(client, buf, 1);
262 if (nread < 0) {
263 perror("recv");
264 return;
265 }
266
267 fd = -1;
268 switch (buf[0]) {
269
270 case '4':
271 fprintf(stderr, "for ICMPv4 socket\n");
272 fd = mkrawsock(PF_INET);
273 break;
274
275 case '6':
276 fprintf(stderr, "for ICMPv6 socket\n");
277 fd = mkrawsock(PF_INET6);
278 break;
279
280 default:
281 fprintf(stderr, "bad request 0x%02x\n", (unsigned int)buf[0]);
282 return;
283 }
284
285 if (fd < 0) {
286 buf[0] = '\0'; /* NAK */
287 nsent = write(client, buf, 1);
288 (void)nsent;
289 return;
290 }
291
292 memset(&mh, 0, sizeof(mh));
293 memset(cmsg, 0, sizeof(cmsg));
294
295 iov[0].iov_base = buf;
296 iov[0].iov_len = 1;
297
298 mh.msg_iov = iov;
299 mh.msg_iovlen = 1;
300 mh.msg_control = cmsg;
301 mh.msg_controllen = sizeof(cmsg);
302
303 cmh = CMSG_FIRSTHDR(&mh);
304 cmh->cmsg_level = SOL_SOCKET;
305 cmh->cmsg_type = SCM_RIGHTS;
306 cmh->cmsg_len = CMSG_LEN(sizeof(fd));
307 *((int *) CMSG_DATA(cmh)) = fd;
308
309 nsent = sendmsg(client, &mh, 0);
310 if (nsent < 0) {
311 perror("sendmsg");
312 }
313
314 close(fd);
315}
316
317
318static int
319mkrawsock(int family)
320{
321 int fd;
322
323 if (family == PF_INET) {
324 fd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
325 if (fd < 0) {
326 perror("IPPROTO_ICMP");
327 return -1;
328 }
329 }
330 else {
331 fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
332 if (fd < 0) {
333 perror("IPPROTO_ICMPV6");
334 return -1;
335 }
336 }
337
338 return fd;
339}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette