1 /*
2 * Copyright (c) 2009, Giampaolo Rodola'.
3 * Copyright (c) 2015, Ryo ONODERA.
4 * All rights reserved.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include <Python.h>
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/sysctl.h>
14 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <netinet/in.h>
17 #include <string.h>
18 #include <sys/cdefs.h>
19 #include <arpa/inet.h>
20 #include <sys/queue.h>
21 #include <sys/un.h>
22 #include <sys/file.h>
23
24 #include "../../_psutil_common.h"
25 #include "../../_psutil_posix.h"
26
27
28 // address family filter
29 enum af_filter {
30 INET,
31 INET4,
32 INET6,
33 TCP,
34 TCP4,
35 TCP6,
36 UDP,
37 UDP4,
38 UDP6,
39 UNIX,
40 ALL,
41 };
42
43 // kinfo_file results
44 struct kif {
45 SLIST_ENTRY(kif) kifs;
46 struct kinfo_file *kif;
47 };
48
49 // kinfo_file results list
50 SLIST_HEAD(kifhead, kif) kihead = SLIST_HEAD_INITIALIZER(kihead);
51
52
53 // kinfo_pcb results
54 struct kpcb {
55 SLIST_ENTRY(kpcb) kpcbs;
56 struct kinfo_pcb *kpcb;
57 };
58
59 // kinfo_pcb results list
60 SLIST_HEAD(kpcbhead, kpcb) kpcbhead = SLIST_HEAD_INITIALIZER(kpcbhead);
61
62 static void psutil_kiflist_init(void);
63 static void psutil_kiflist_clear(void);
64 static void psutil_kpcblist_init(void);
65 static void psutil_kpcblist_clear(void);
66 static int psutil_get_files(void);
67 static int psutil_get_sockets(const char *name);
68 static int psutil_get_info(int aff);
69
70
71 // Initialize kinfo_file results list.
72 static void
psutil_kiflist_init(void)73 psutil_kiflist_init(void) {
74 SLIST_INIT(&kihead);
75 return;
76 }
77
78
79 // Clear kinfo_file results list.
80 static void
psutil_kiflist_clear(void)81 psutil_kiflist_clear(void) {
82 while (!SLIST_EMPTY(&kihead)) {
83 SLIST_REMOVE_HEAD(&kihead, kifs);
84 }
85
86 return;
87 }
88
89
90 // Initialize kinof_pcb result list.
91 static void
psutil_kpcblist_init(void)92 psutil_kpcblist_init(void) {
93 SLIST_INIT(&kpcbhead);
94 return;
95 }
96
97
98 // Clear kinof_pcb result list.
99 static void
psutil_kpcblist_clear(void)100 psutil_kpcblist_clear(void) {
101 while (!SLIST_EMPTY(&kpcbhead)) {
102 SLIST_REMOVE_HEAD(&kpcbhead, kpcbs);
103 }
104
105 return;
106 }
107
108
109 // Get all open files including socket.
110 static int
psutil_get_files(void)111 psutil_get_files(void) {
112 size_t len;
113 size_t j;
114 int mib[6];
115 char *buf;
116 off_t offset;
117
118 mib[0] = CTL_KERN;
119 mib[1] = KERN_FILE2;
120 mib[2] = KERN_FILE_BYFILE;
121 mib[3] = 0;
122 mib[4] = sizeof(struct kinfo_file);
123 mib[5] = 0;
124
125 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
126 PyErr_SetFromErrno(PyExc_OSError);
127 return -1;
128 }
129
130 offset = len % sizeof(off_t);
131 mib[5] = len / sizeof(struct kinfo_file);
132
133 if ((buf = malloc(len + offset)) == NULL) {
134 PyErr_NoMemory();
135 return -1;
136 }
137
138 if (sysctl(mib, 6, buf + offset, &len, NULL, 0) == -1) {
139 free(buf);
140 PyErr_SetFromErrno(PyExc_OSError);
141 return -1;
142 }
143
144 len /= sizeof(struct kinfo_file);
145 struct kinfo_file *ki = (struct kinfo_file *)(buf + offset);
146
147 for (j = 0; j < len; j++) {
148 struct kif *kif = malloc(sizeof(struct kif));
149 kif->kif = &ki[j];
150 SLIST_INSERT_HEAD(&kihead, kif, kifs);
151 }
152
153 /*
154 // debug
155 struct kif *k;
156 SLIST_FOREACH(k, &kihead, kifs) {
157 printf("%d\n", k->kif->ki_pid); // NOQA
158 }
159 */
160
161 return 0;
162 }
163
164
165 // Get open sockets.
166 static int
psutil_get_sockets(const char * name)167 psutil_get_sockets(const char *name) {
168 size_t namelen;
169 int mib[8];
170 struct kinfo_pcb *pcb;
171 size_t len;
172 size_t j;
173
174 memset(mib, 0, sizeof(mib));
175
176 if (sysctlnametomib(name, mib, &namelen) == -1) {
177 PyErr_SetFromErrno(PyExc_OSError);
178 return -1;
179 }
180
181 if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1) {
182 PyErr_SetFromErrno(PyExc_OSError);
183 return -1;
184 }
185
186 if ((pcb = malloc(len)) == NULL) {
187 PyErr_NoMemory();
188 return -1;
189 }
190 memset(pcb, 0, len);
191
192 mib[6] = sizeof(*pcb);
193 mib[7] = len / sizeof(*pcb);
194
195 if (sysctl(mib, __arraycount(mib), pcb, &len, NULL, 0) == -1) {
196 free(pcb);
197 PyErr_SetFromErrno(PyExc_OSError);
198 return -1;
199 }
200
201 len /= sizeof(struct kinfo_pcb);
202 struct kinfo_pcb *kp = (struct kinfo_pcb *)pcb;
203
204 for (j = 0; j < len; j++) {
205 struct kpcb *kpcb = malloc(sizeof(struct kpcb));
206 kpcb->kpcb = &kp[j];
207 SLIST_INSERT_HEAD(&kpcbhead, kpcb, kpcbs);
208 }
209 return 0;
210 }
211
212
213 // Collect open file and connections.
214 static int
psutil_get_info(int aff)215 psutil_get_info(int aff) {
216 switch (aff) {
217 case INET:
218 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
219 return -1;
220 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
221 return -1;
222 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
223 return -1;
224 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
225 return -1;
226 break;
227 case INET4:
228 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
229 return -1;
230 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
231 return -1;
232 break;
233 case INET6:
234 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
235 return -1;
236 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
237 return -1;
238 break;
239 case TCP:
240 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
241 return -1;
242 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
243 return -1;
244 break;
245 case TCP4:
246 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
247 return -1;
248 break;
249 case TCP6:
250 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
251 return -1;
252 break;
253 case UDP:
254 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
255 return -1;
256 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
257 return -1;
258 break;
259 case UDP4:
260 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
261 return -1;
262 break;
263 case UDP6:
264 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
265 return -1;
266 break;
267 case UNIX:
268 if (psutil_get_sockets("net.local.stream.pcblist") != 0)
269 return -1;
270 if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
271 return -1;
272 if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
273 return -1;
274 break;
275 case ALL:
276 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
277 return -1;
278 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
279 return -1;
280 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
281 return -1;
282 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
283 return -1;
284 if (psutil_get_sockets("net.local.stream.pcblist") != 0)
285 return -1;
286 if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
287 return -1;
288 if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
289 return -1;
290 break;
291 }
292
293 return 0;
294 }
295
296
297 /*
298 * Return system-wide connections (unless a pid != -1 is passed).
299 */
300 PyObject *
psutil_net_connections(PyObject * self,PyObject * args)301 psutil_net_connections(PyObject *self, PyObject *args) {
302 char laddr[PATH_MAX];
303 char raddr[PATH_MAX];
304 int32_t lport;
305 int32_t rport;
306 int32_t status;
307 pid_t pid;
308 PyObject *py_tuple = NULL;
309 PyObject *py_laddr = NULL;
310 PyObject *py_raddr = NULL;
311 PyObject *py_retlist = PyList_New(0);
312
313 if (py_retlist == NULL)
314 return NULL;
315
316 if (! PyArg_ParseTuple(args, "l", &pid))
317 return NULL;
318
319 psutil_kiflist_init();
320 psutil_kpcblist_init();
321 if (psutil_get_files() != 0)
322 goto error;
323 if (psutil_get_info(ALL) != 0)
324 goto error;
325
326 struct kif *k;
327 SLIST_FOREACH(k, &kihead, kifs) {
328 struct kpcb *kp;
329 if ((pid != -1) && (k->kif->ki_pid != (unsigned int)pid))
330 continue;
331 SLIST_FOREACH(kp, &kpcbhead, kpcbs) {
332 if (k->kif->ki_fdata != kp->kpcb->ki_sockaddr)
333 continue;
334
335 // IPv4 or IPv6
336 if ((kp->kpcb->ki_family == AF_INET) ||
337 (kp->kpcb->ki_family == AF_INET6)) {
338
339 if (kp->kpcb->ki_family == AF_INET) {
340 // IPv4
341 struct sockaddr_in *sin_src =
342 (struct sockaddr_in *)&kp->kpcb->ki_src;
343 struct sockaddr_in *sin_dst =
344 (struct sockaddr_in *)&kp->kpcb->ki_dst;
345 // source addr and port
346 inet_ntop(AF_INET, &sin_src->sin_addr, laddr,
347 sizeof(laddr));
348 lport = ntohs(sin_src->sin_port);
349 // remote addr and port
350 inet_ntop(AF_INET, &sin_dst->sin_addr, raddr,
351 sizeof(raddr));
352 rport = ntohs(sin_dst->sin_port);
353 }
354 else {
355 // IPv6
356 struct sockaddr_in6 *sin6_src =
357 (struct sockaddr_in6 *)&kp->kpcb->ki_src;
358 struct sockaddr_in6 *sin6_dst =
359 (struct sockaddr_in6 *)&kp->kpcb->ki_dst;
360 // local addr and port
361 inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr,
362 sizeof(laddr));
363 lport = ntohs(sin6_src->sin6_port);
364 // remote addr and port
365 inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr,
366 sizeof(raddr));
367 rport = ntohs(sin6_dst->sin6_port);
368 }
369
370 // status
371 if (kp->kpcb->ki_type == SOCK_STREAM)
372 status = kp->kpcb->ki_tstate;
373 else
374 status = PSUTIL_CONN_NONE;
375
376 // build addr tuple
377 py_laddr = Py_BuildValue("(si)", laddr, lport);
378 if (! py_laddr)
379 goto error;
380 if (rport != 0)
381 py_raddr = Py_BuildValue("(si)", raddr, rport);
382 else
383 py_raddr = Py_BuildValue("()");
384 if (! py_raddr)
385 goto error;
386 }
387 else if (kp->kpcb->ki_family == AF_UNIX) {
388 // UNIX sockets
389 struct sockaddr_un *sun_src =
390 (struct sockaddr_un *)&kp->kpcb->ki_src;
391 struct sockaddr_un *sun_dst =
392 (struct sockaddr_un *)&kp->kpcb->ki_dst;
393 strcpy(laddr, sun_src->sun_path);
394 strcpy(raddr, sun_dst->sun_path);
395 status = PSUTIL_CONN_NONE;
396 py_laddr = PyUnicode_DecodeFSDefault(laddr);
397 if (! py_laddr)
398 goto error;
399 py_raddr = PyUnicode_DecodeFSDefault(raddr);
400 if (! py_raddr)
401 goto error;
402 }
403 else {
404 continue;
405 }
406
407 // append tuple to list
408 py_tuple = Py_BuildValue(
409 "(iiiOOii)",
410 k->kif->ki_fd,
411 kp->kpcb->ki_family,
412 kp->kpcb->ki_type,
413 py_laddr,
414 py_raddr,
415 status,
416 k->kif->ki_pid);
417 if (! py_tuple)
418 goto error;
419 if (PyList_Append(py_retlist, py_tuple))
420 goto error;
421 Py_DECREF(py_laddr);
422 Py_DECREF(py_raddr);
423 Py_DECREF(py_tuple);
424 }
425 }
426
427 psutil_kiflist_clear();
428 psutil_kpcblist_clear();
429 return py_retlist;
430
431 error:
432 Py_XDECREF(py_tuple);
433 Py_XDECREF(py_laddr);
434 Py_XDECREF(py_raddr);
435 return 0;
436 }
437