Codebase list nsntrace / fc4c895
New upstream version 4 Sudip Mukherjee 3 years ago
11 changed file(s) with 388 addition(s) and 59 deletion(s). Raw diff Collapse all Expand all
0 #nsntrace
0 # nsntrace
11 > Perform network trace of a single process by using network namespaces.
22
33 This application uses Linux network namespaces to perform network traces of a single application. The traces are saved as pcap files. And can later be analyzed by for instance Wireshark.
2828 Another limitation is, that since we are using iptables and since
2929 we are tracing raw sockets. This application needs to be run as root.
3030
31 On many systems today the nameserver functionality is handled by an
32 application such as systemd-resolved or dnsmasq and the nameserver
33 address is a loopback address (like 127.0.0.53) where that application
34 listens for incoming DNS queries.
35
36 This will not work for us in this network namespace environment, since
37 we have our own namespaced loopback device. To work around this one can use the
38 `--use-public-dns` option to override resolv.conf in the namespace. Then nsntrace
39 will use nameservers from Quad9 (9.9.9.9), Cloudflare (1.1.1.1), Google (8.8.8.8) and
40 OpenDNS (208.67.222.222) to perform DNS queries.
41
3142 ## usage
32 > nsntrace
43 $ nsntrace
3344 usage: nsntrace [options] program [arguments]
3445 Perform network trace of a single process by using network namespaces.
3546
3647 Options:
37 -o file send trace output to file (default nsntrace.pcap)
38 -d device the network device to trace
39 -f filter an optional capture filter
40 -u username run program as username/uid
48 -o file send trace output to file (default nsntrace.pcap)
49 -d device the network device to trace
50 -f filter an optional capture filter
51 -u username run program as username/uid
52 --use-public-dns override resolv.conf to use public nameservers from
53 Quad9, Cloudflare, Google and OpenDNS
4154
4255 ## example
43 > sudo nsntrace -d eth1 wget www.google.com
44 Starting network trace of 'wget' on interface eth1.
45 Your IP address in this trace is 172.16.42.255.
46 Use ctrl-c to end at any time.
56 ```
57 $ sudo nsntrace -d eth1 wget www.google.com
58 Starting network trace of 'wget' on interface eth1.
59 Your IP address in this trace is 172.16.42.255.
60 Use ctrl-c to end at any time.
4761
48 --2016-07-15 12:12:17-- http://www.google.com/
49 Location: http://www.google.se/?gfe_rd=cr&ei=AbeIV5zZHcaq8wfTlrjgCA [following]
50 --2016-07-15 12:12:17-- http://www.google.se/?gfe_rd=cr&ei=AbeIV5zZHcaq8wfTlrjgCA
51 Length: unspecified [text/html]
52 Saving to: ‘index.html’
62 --2016-07-15 12:12:17-- http://www.google.com/
63 Location: http://www.google.se/?gfe_rd=cr&ei=AbeIV5zZHcaq8wfTlrjgCA [following]
64 --2016-07-15 12:12:17-- http://www.google.se/?gfe_rd=cr&ei=AbeIV5zZHcaq8wfTlrjgCA
65 Length: unspecified [text/html]
66 Saving to: ‘index.html’
5367
54 index.html [ <=> ] 10.72K --.-KB/s in 0.001s
68 index.html [ <=> ] 10.72K --.-KB/s in 0.001s
5569
56 2016-07-15 12:12:17 (15.3 MB/s) - ‘index.html’ saved [10980]
70 2016-07-15 12:12:17 (15.3 MB/s) - ‘index.html’ saved [10980]
5771
58 Finished capturing 42 packets.
72 Finished capturing 42 packets.
5973
60 > tshark -r nsntrace.pcap -Y 'http.response or http.request'
61 16 0.998839 172.16.42.255 -> 195.249.146.104 HTTP 229 GET http://www.google.com/ HTTP/1.1
62 20 1.010671 195.249.146.104 -> 172.16.42.255 HTTP 324 HTTP/1.1 302 Moved Temporarily (text/html)
63 22 1.010898 172.16.42.255 -> 195.249.146.104 HTTP 263 GET http://www.google.se/?gfe_rd=cr&ei=AbeIV5zZHcaq8wfTlrjgCA HTTP/1.1
64 31 1.051006 195.249.146.104 -> 172.16.42.255 HTTP 71 HTTP/1.1 200 OK (text/html)
74 $ tshark -r nsntrace.pcap -Y 'http.response or http.request'
75 16 0.998839 172.16.42.255 -> 195.249.146.104 HTTP 229 GET http://www.google.com/ HTTP/1.1
76 20 1.010671 195.249.146.104 -> 172.16.42.255 HTTP 324 HTTP/1.1 302 Moved Temporarily (text/html)
77 22 1.010898 172.16.42.255 -> 195.249.146.104 HTTP 263 GET http://www.google.se/?gfe_rd=cr&ei=AbeIV5zZHcaq8wfTlrjgCA HTTP/1.1
78 31 1.051006 195.249.146.104 -> 172.16.42.255 HTTP 71 HTTP/1.1 200 OK (text/html)
79 ```
80
81 ### live capture using tshark
82 ```
83 $ sudo nsntrace -f tcp -o - wget www.google.com 2> /dev/null | tshark -r -
84 1 0.000000 172.16.42.255 → 142.250.74.36 TCP 74 51088 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=1362504482 TSecr=0 WS=128
85 2 0.014010 142.250.74.36 → 172.16.42.255 TCP 74 80 → 51088 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1430 SACK_PERM=1 TSval=2846449454 Secr=1362504482 WS=256
86 3 0.014078 172.16.42.255 → 142.250.74.36 TCP 66 51088 → 80 [ACK] Seq=1 Ack=1 Win=64256 Len=0 TSval=1362504496 TSecr=2846449454
87 4 0.014221 172.16.42.255 → 142.250.74.36 HTTP 207 GET / HTTP/1.1
88
89 5 0.033935 142.250.74.36 → 172.16.42.255 TCP 66 80 → 51088 [ACK] Seq=1 Ack=142 Win=66816 Len=0 TSval=2846449475 TSecr=1362504496
90 6 0.093989 142.250.74.36 → 172.16.42.255 TCP 1484 HTTP/1.1 200 OK [TCP segment of a reassembled PDU]
91 7 0.094022 172.16.42.255 → 142.250.74.36 TCP 66 51088 → 80 [ACK] Seq=142 Ack=1419 Win=63360 Len=0 TSval=1362504576 TSecr=2846449532
92 8 0.096447 142.250.74.36 → 172.16.42.255 TCP 2902 HTTP/1.1 200 OK [TCP segment of a reassembled PDU]
93 9 0.096478 172.16.42.255 → 142.250.74.36 TCP 66 51088 → 80 [ACK] Seq=142 Ack=4255 Win=62208 Len=0 TSval=1362504578 TSecr=2846449532
94 10 0.099871 142.250.74.36 → 172.16.42.255 HTTP 9626 Continuation[Packet size limited during capture]
95 11 0.099936 172.16.42.255 → 142.250.74.36 TCP 66 51088 → 80 [ACK] Seq=142 Ack=13815 Win=56320 Len=0 TSval=1362504582 TSecr=2846449532
96 12 0.100743 172.16.42.255 → 142.250.74.36 TCP 66 51088 → 80 [FIN, ACK] Seq=142 Ack=13815 Win=64128 Len=0 TSval=1362504583 TSecr=2846449532
97 13 0.113167 142.250.74.36 → 172.16.42.255 TCP 66 80 → 51088 [FIN, ACK] Seq=13815 Ack=143 Win=66816 Len=0 TSval=2846449554 TSecr=1362504583
98 14 0.113190 172.16.42.255 → 142.250.74.36 TCP 66 51088 → 80 [ACK] Seq=143 Ack=13816 Win=64128 Len=0 TSval=1362504595 TSecr=2846449554
99 ```
22 # [bug reports],
33 # [tar-ball name])
44 AC_INIT([nsntrace],
5 [3],
5 [4],
66 [https://github.com/jonasdn/nsntrace/issues],
77 [nsntrace])
88
7676 </para></listitem>
7777 </varlistentry>
7878
79
80 <varlistentry>
81 <term><option>--use-public-dns</option></term>
82 <listitem><para>
83 Override resolv.conf in namespace to use public nameservers from
84 Quad9 (9.9.9.9), Cloudflare (1.1.1.1), Google (8.8.8.8) and
85 OpenDNS (208.67.222.222).
86 </para></listitem>
87 </varlistentry>
88
7989 <varlistentry>
8090 <term><option>--outfile <replaceable>file</replaceable></option></term>
8191 <term><option>-o <replaceable>file</replaceable></option></term>
8292
8393 <listitem><para>
8494 Write the trace output to the file <replaceable>file</replaceable>.
85 Default is nsntrace.pcap.
95 Default is nsntrace.pcap. Use '-' for stdout.
8696 </para></listitem>
8797 </varlistentry>
8898
0 name: nsntrace
1 adopt-info: nsntrace
2 base: core20
3 summary: Namespaced network tracer
4 description: |
5 Perform network trace of a single process by using network namespaces.
6
7 grade: stable
8 confinement: classic
9
10 parts:
11 nsntrace:
12 plugin: autotools
13 source-type: git
14 override-pull: | # This override tells snapcraft to use latest release tag
15 snapcraftctl pull
16 last_tag="$(git describe --tags --abbrev=0 --match 'v*')"
17 git fetch
18 git checkout "${last_tag}"
19 snapcraftctl set-version "${last_tag}"
20 source: https://github.com/nsntrace/nsntrace.git
21 build-packages:
22 - libpcap-dev
23 - libnl-route-3-dev
24 - xsltproc
25 - iptables
26 - pkg-config
27 - docbook-xsl
28 - docbook-xml
29 stage-packages:
30 - libpcap0.8
31
32 apps:
33 nsntrace:
34 command: usr/local/bin/nsntrace
1515 nsntrace_SOURCES = $(headers) $(sources)
1616 nsntrace_CPPFLAGS = $(LIBNL_CFLAGS) $(warnings)
1717 nsntrace_LDFLAGS = -pthread
18 nsntrace_LDADD = $(LIBNL_LIBS)
18 nsntrace_LDADD = $(LIBNL_LIBS) -lresolv
1212 * with nsntraces; if not, see <https://www.gnu.org/licenses/>.
1313 */
1414
15 #include <linux/if.h>
1516 #include <pcap.h>
1617 #include <pthread.h>
1718 #include <stdlib.h>
5758 nsntrace_capture_stop()
5859 {
5960 pcap_breakloop(handle);
60 pthread_join(capture_thread, NULL);
6161 }
6262
6363 int
6464 nsntrace_capture_start(const char *iface,
6565 const char *filter,
66 const char *outfile)
66 FILE *fp)
6767 {
6868 char errbuf[PCAP_ERRBUF_SIZE];
69 struct bpf_program fp;
69 struct bpf_program bpf_fp;
7070 int ret;
7171
7272 if (!(handle = pcap_open_live(iface, BUFSIZ, 1, 1000, errbuf))) {
7575 }
7676
7777 if (filter) {
78 ret = pcap_compile(handle, &fp, filter,
78 ret = pcap_compile(handle, &bpf_fp, filter,
7979 0, PCAP_NETMASK_UNKNOWN);
8080 if (ret < 0) {
8181 fprintf(stderr, "Failed to set filter: %s\n", filter);
8282 return EXIT_FAILURE;
8383 } else {
84 pcap_setfilter(handle, &fp);
84 pcap_setfilter(handle, &bpf_fp);
8585 }
8686 }
8787
88 if (!(pcap_dumper = pcap_dump_open(handle, outfile))) {
89 fprintf(stderr, "Couldn't open output: %s: %s\n",
90 outfile, pcap_geterr(handle));
88 if (!(pcap_dumper = pcap_dump_fopen(handle, fp))) {
89 fprintf(stderr, "Couldn't open output: %s\n", pcap_geterr(handle));
9190 return EXIT_FAILURE;
9291 }
9392
116115 char *
117116 nsntrace_capture_default_device()
118117 {
119 return pcap_lookupdev(NULL);
118 pcap_if_t *interfaces;
119 char *name;
120
121 if (pcap_findalldevs(&interfaces, NULL) < 0) {
122 return NULL;
123 }
124
125 name = strndup(interfaces->name, IFNAMSIZ);
126 pcap_freealldevs(interfaces);
127
128 return name;
120129 }
121130
122131 int
124133 {
125134 pcap_if_t *dev;
126135 pcap_if_t *devList;
136 int ret = EXIT_FAILURE;
127137
128138 char errbuf[PCAP_ERRBUF_SIZE];
129139
134144
135145 for (dev = devList; dev != NULL; dev = dev->next) {
136146 if (strcmp(dev->name, iface) == 0) {
137 return EXIT_SUCCESS;
147 ret = EXIT_SUCCESS;
148 goto out;
138149 }
139150 }
140151
141152 fprintf(stderr, "Unknown interface: %s\n", iface);
142
143 return EXIT_FAILURE;
153 out:
154 pcap_freealldevs(devList);
155 return ret;
144156 }
1717
1818 int nsntrace_capture_start(const char *iface,
1919 const char *filter,
20 const char *outfile);
20 FILE *fp);
2121
2222 void nsntrace_capture_stop();
2323
1313 *
1414 */
1515
16 #define _GNU_SOURCE
17 #include <errno.h>
1618 #include <fcntl.h>
1719 #include <sys/socket.h>
1820 #include <linux/if.h>
2628 #include <netlink/route/link/bonding.h>
2729 #include <netlink/route/link/veth.h>
2830 #include <netlink/route/route.h>
31 #include <resolv.h>
32 #include <sched.h>
2933 #include <sys/ioctl.h>
34 #include <sys/mount.h>
3035 #include <sys/socket.h>
36 #include <sys/stat.h>
3137 #include <unistd.h>
3238
3339 #include "cmd.h"
40 #include "net.h"
3441
3542 /*
3643 * Netlink is an IPC mechanism used between the kernel and user space
274281 }
275282
276283 /*
284 * This function will create a namespace local resolv.conf that will
285 * take precedence over the system-wide one. It uses the black magic
286 * of mount namespaces.
287 *
288 * It is a best-effort thing, so it will not return any error, but report
289 * when things go bad.
290 */
291 static void
292 _nsntrace_net_create_resolv_conf()
293 {
294 int fd;
295 const char *resolv = "nameserver 9.9.9.9\n" /* Quad9 */
296 "nameserver 1.1.1.1\n" /* Cloudflare */
297 "nameserver 8.8.8.8\n" /* Google */
298 "nameserver 208.67.222.222\n"; /* OpenDNS */
299
300 if (mkdir(NSNTRACE_RUN_DIR, 0644) < 0) {
301 if (errno != EEXIST) {
302 perror("mkdir");
303 return;
304 }
305 }
306
307 char resolv_path[] = NSNTRACE_RUN_DIR "/resolv.confXXXXXX";
308 if ((fd = mkstemp(resolv_path)) < 0) {
309 perror("mkstemp");
310 return;
311 }
312
313 if (write(fd, resolv, strlen(resolv) + 1) < 0) {
314 perror("write");
315 close(fd);
316 return;
317 }
318
319 close(fd);
320
321 /*
322 * Here we will get a bit tricky. In order to have our own nameservers
323 * for our network namespace we will bind mount our own resolv.conf
324 * over the system-wide one at /etc/resolv.conf.
325 *
326 * But we do not want to affect others outside this namespace. So we
327 * enter a mount namespace (CLONE_NEWNS) before we do the bind mount. This,
328 * however, is not enough. Before the bind mount we need to remount the
329 * root partition with the MS_SLAVE and MS_REC flags to make sure our
330 * changes are not propagated to the outside mount namespace. As some
331 * systems have that as the default behavior.
332 */
333
334 /* enter new mount namespace */
335 if (unshare(CLONE_NEWNS) < 0) {
336 perror("unshare");
337 return;
338 }
339
340 /* remount root to avoid propagating changes to subtrees */
341 if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
342 perror("mount");
343 return;
344 }
345
346 /* bind mount our resolv.conf over system-wide */
347 if (mount(resolv_path, "/etc/resolv.conf", "none", MS_BIND, NULL) < 0) {
348 perror("mount");
349 return;
350 }
351 }
352
353 /*
354 * Here we use the resolver(3) family of functions to iterate through the
355 * configured nameservers.
356 *
357 * On many systems today the nameserver functionality is handled by an
358 * application such as systemd-resolved or dnsmasq and the nameserver address
359 * is a loopback address (like 127.0.0.53) where that application listens for
360 * incoming DNS queries.
361 *
362 * This will not work for us in this network namespace environment, since
363 * we have our own namespaced loopback device.
364 */
365 static void
366 _nsntrace_net_check_dns()
367 {
368 struct __res_state resolv_state = { 0, };
369
370 if (res_ninit(&resolv_state) < 0) {
371 return;
372 }
373
374 /* iterate configured nameservers */
375 for (int i = 0; i < MAXNS; i++) {
376 struct in_addr addr = resolv_state.nsaddr_list[i].sin_addr;
377 if (addr.s_addr == 0) {
378 continue;
379 }
380 /* s_addr is a 32 bit integer representing the ipv4 address */
381 unsigned char first = addr.s_addr & 0x000000FF;
382 if (first == 127)
383 continue;
384 return; /* non-loopback nameserver found */
385 }
386
387 /* we end up here if we did not find any non-loopback nameserver */
388 fprintf(stderr,
389 "Warning: only loopback (127.x.y.z) nameservers found.\n"
390 "This means we will probably not be able to resolve hostnames.\n"
391 "Consider passing --use-public-dns to use public nameservers from\n"
392 "Quad9, Cloudflare, Google and OpenDNS\n\n");
393 }
394
395 /*
277396 * Set up the environment needed from the root network namespace point
278397 * of view. Create virtual ethernet interface (see above) and set our side
279398 * of it up and set address.
329448 * Set up the namespaced net infrastructure needed.
330449 */
331450 int
332 nsntrace_net_ns_init()
451 nsntrace_net_ns_init(int use_public_dns)
333452 {
334453 int ret = 0;
335454
341460 return EXIT_FAILURE;
342461 }
343462
463 if (!use_public_dns) {
464 _nsntrace_net_check_dns();
465 } else {
466 _nsntrace_net_create_resolv_conf();
467 }
344468
345469 return ret;
346470 }
1515 #ifndef _NSNTRACE_NET_H_
1616 #define _NSNTRACE_NET_H
1717
18 #define NSNTRACE_RUN_DIR "/run/nsntrace"
19
1820 int nsntrace_net_init(pid_t ns_pid,
1921 const char *device);
2022
2123 int nsntrace_net_deinit(const char *device);
2224
23 int nsntrace_net_ns_init();
25 int nsntrace_net_ns_init(int use_public_dns);
2426
2527 int nsntrace_net_ip_forward_enabled();
2628
1313 *
1414 */
1515 #define _GNU_SOURCE
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <ftw.h>
1619 #include <grp.h>
1720 #include <getopt.h>
21 #include <linux/limits.h>
1822 #include <sched.h>
1923 #include <signal.h>
2024 #include <stdio.h>
2125 #include <stdlib.h>
2226 #include <string.h>
27 #include <sys/mount.h>
2328 #include <sys/wait.h>
29 #include <sys/stat.h>
2430 #include <time.h>
2531 #include <unistd.h>
2632 #include <pwd.h>
6167
6268 #define STACK_SIZE (1024 * 64) /* 64 kB stack */
6369 #define DEFAULT_OUTFILE "nsntrace.pcap"
70 #define NETNS_RUN_DIR "/run/netns"
71 #define PROC_SELF_NETNS_PATH "/proc/self/ns/net"
72
73 static FILE *where;
6474
6575 struct nsntrace_options {
6676 char *outfile;
6777 char *device;
78 int use_public_dns;
6879 char *user;
6980 char *filter;
7081 char * const *args;
7182 };
7283
84 #define PUBLIC_DNS 1000
7385 static const char *short_opt = "+o:d:u:f:h";
7486 static struct option long_opt[] = {
7587 { "outfile", required_argument, NULL, 'o' },
7688 { "device", required_argument, NULL, 'd' },
89 { "use-public-dns", no_argument, NULL, PUBLIC_DNS },
7790 { "user", required_argument, NULL, 'u' },
7891 { "filter", required_argument, NULL, 'f' },
7992 { "help", required_argument, NULL, 'h' },
121134 }
122135 }
123136
137 static int _nsntrace_unlink_cb(const char *fpath,
138 const struct stat *sb,
139 int typeflag,
140 struct FTW *ftwbuf)
141 {
142 int rv = remove(fpath);
143 if (rv)
144 perror(fpath);
145 return rv;
146 }
147
148 static void _nsntrace_remove_ns()
149 {
150 char netns_path[PATH_MAX];
151
152 snprintf(netns_path, sizeof(netns_path), "%s/nsntrace-%d", NETNS_RUN_DIR, getpid());
153 umount2(netns_path, MNT_DETACH);
154 if (unlink(netns_path) < 0) {
155 perror("unlink");
156 }
157
158 /* clean up run-time files */
159 nftw(NSNTRACE_RUN_DIR, _nsntrace_unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
160 }
161
124162 static void
125163 _nsntrace_cleanup_ns()
126164 {
127165 kill(child_pid, SIGTERM);
128166 waitpid(child_pid, NULL, 0);
129167
130 printf("Finished capturing %lu packets.\n",
131 nsntrace_capture_packet_count());
168 _nsntrace_remove_ns();
169
170 fprintf(where, "Finished capturing %lu packets.\n",
171 nsntrace_capture_packet_count());
132172 nsntrace_capture_flush();
133173 }
134174
146186 * terminating signals. We need to clean up after
147187 * our children.
148188 */
149 printf("Capture interrupted, cleaning up\n");
150
151 /* wait for our children */
152189 wait(NULL);
190 }
191
192 /*
193 * This will give the network namespace a name in the eyes of tools like
194 * ip-netns. We need to make sure we clean up after us, since a bind mount
195 * of /proc/<pid>/ns/net will keep the network namespace alive after the
196 * process exits.
197 */
198 static void
199 _nsntrace_set_name()
200 {
201 char netns_path[PATH_MAX];
202 int fd;
203 int ret = 0;
204
205 /* Create the base netns directory if it doesn't exist */
206 if ((ret = mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) < 0) {
207 if (errno != EEXIST) {
208 goto out;
209 }
210 }
211
212 snprintf(netns_path, PATH_MAX, "%s/nsntrace-%d", NETNS_RUN_DIR, getpid());
213 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
214 if (fd < 0) {
215 ret = fd;
216 goto out;
217 }
218 close(fd);
219
220 ret = mount(PROC_SELF_NETNS_PATH, netns_path, "none", MS_BIND, NULL);
221 out:
222 if (ret < 0) {
223 fprintf(stderr, "failed to set namespace name\n");
224 }
153225 }
154226
155227 static void
159231 const char *ip;
160232 const char *interface;
161233
234 /*
235 * If outfile is a lone dash ("-"), the user wants us to output to STDOUT,
236 * in that case we avoid printing anything else to STDOUT and use STDERR
237 * instead.
238 */
239 FILE *fp;
240 if (options->outfile[0] == '-' && options->outfile[1] == '\0') {
241 where = stderr;
242 fp = stdout;
243 } else {
244 where = stdout;
245 fp = fopen(options->outfile, "w");
246 if (!fp) {
247 perror("fopen");
248 exit(EXIT_FAILURE);
249 }
250 }
251
162252 ip = nsntrace_net_get_capture_ip();
163253 interface = nsntrace_net_get_capture_interface();
164254
165 printf("Starting network trace of '%s' on interface %s.\n"
166 "Your IP address in this trace is %s.\n"
167 "Use ctrl-c to end at any time.\n\n",
168 options->args[0], options->device, ip);
169 ret = nsntrace_capture_start(interface, options->filter, options->outfile);
255 fprintf(where, "Starting network trace of '%s' on interface %s.\n"
256 "Your IP address in this trace is %s.\n"
257 "Use ctrl-c to end at any time.\n\n",
258 options->args[0], options->device, ip);
259 ret = nsntrace_capture_start(interface, options->filter, fp);
170260 if (ret != 0) {
171261 exit(ret);
172262 }
234324 exit(EXIT_FAILURE);
235325 }
236326
327 /*
328 * If outfile is a lone dash we output only PCAP data on STDOUT.
329 * We use the dup2 syscall to redirect the tracee output to STDERR.
330 */
331 if (options->outfile[0] == '-' && options->outfile[1] == '\0') {
332 dup2(STDERR_FILENO, STDOUT_FILENO);
333 }
334
237335 /* launch the application to trace */
238336 if (execvp(options->args[0], options->args) < 0) {
239337 fprintf(stderr, "Unable to start '%s'\n", options->args[0]);
247345 int ret = EXIT_SUCCESS;
248346 struct nsntrace_options *options = (struct nsntrace_options *) arg;
249347
250 if (nsntrace_net_ns_init() < 0) {
348 if (nsntrace_net_ns_init(options->use_public_dns) < 0) {
251349 fprintf(stderr, "failed to setup network environment\n");
252350 return EXIT_FAILURE;
253351 }
254352
255353 _nsntrace_handle_signals(_nsntrace_cleanup_ns_signal_callback);
256354 _nsntrace_start_tracer(options);
355
356 _nsntrace_set_name();
257357
258358 child_pid = fork();
259359 if (child_pid < 0) {
292392 static void
293393 _nsntrace_usage()
294394 {
295 printf("usage: nsntrace [options] program [arguments]\n"
395 fprintf(stderr, "usage: nsntrace [options] program [arguments]\n"
296396 "Perform network trace of a single process by using "
297397 "network namespaces.\n\n"
298398 "Options:\n"
299 "-o file\t\tsend trace output to file (default nsntrace.pcap)\n"
300 "-d device\tthe network device to trace\n"
301 "-f filter\tan optional capture filter\n"
302 "-u username\trun PROG as username/uid\n");
399 "-o file\t\t\tsend trace output to file (default nsntrace.pcap), use '-' for stdout\n"
400 "-d device\t\tthe network device to trace\n"
401 "-f filter\t\tan optional capture filter\n"
402 "-u username\t\trun PROG as username/uid\n"
403 "--use-public-dns\toverride resolv.conf to use public nameservers from\n"
404 "\t\t\tQuad9, Cloudflare, Google and OpenDNS\n");
303405 }
304406
305407 static void
331433 options->filter = strdup(optarg);
332434 break;
333435
436 case PUBLIC_DNS:
437 options->use_public_dns = 1;
438 break;
439
334440 case 'h':
335441 _nsntrace_usage();
336442 exit(EXIT_SUCCESS);
344450 }
345451
346452 if (!options->device) {
347 options->device = strdup(nsntrace_capture_default_device());
453 options->device = nsntrace_capture_default_device();
348454 }
349455 if (!options->outfile) {
350456 options->outfile = strdup(DEFAULT_OUTFILE);
396502 if ((ret = nsntrace_net_init(pid, options.device)) < 0 ||
397503 (ret = nsntrace_capture_check_device(options.device))) {
398504 fprintf(stderr, "Failed to setup networking environment\n");
399 kill(pid, SIGTERM);
505 kill(pid, SIGKILL);
400506 goto out;
401507 }
402508
1919 exit 1
2020 }
2121
22 ls /run/nsntrace > /dev/null 2>&1 && {
23 echo "run-time files not cleaned up after signal $signal"
24 exit 1
25 }
26
2227 rm -rf *.pcap
2328 }
2429