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);
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
210 /*
211 // debug
212 struct kif *k;
213 struct kpcb *k;
214 SLIST_FOREACH(k, &kpcbhead, kpcbs) {
215 printf("ki_type: %d\n", k->kpcb->ki_type);
216 printf("ki_family: %d\n", k->kpcb->ki_family);
217 }
218 */
219
220 return 0;
221 }
222
223
224 // Collect open file and connections.
225 static int
psutil_get_info(int aff)226 psutil_get_info(int aff) {
227 switch (aff) {
228 case INET:
229 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
230 return -1;
231 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
232 return -1;
233 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
234 return -1;
235 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
236 return -1;
237 break;
238 case INET4:
239 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
240 return -1;
241 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
242 return -1;
243 break;
244 case INET6:
245 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
246 return -1;
247 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
248 return -1;
249 break;
250 case TCP:
251 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
252 return -1;
253 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
254 return -1;
255 break;
256 case TCP4:
257 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
258 return -1;
259 break;
260 case TCP6:
261 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
262 return -1;
263 break;
264 case UDP:
265 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
266 return -1;
267 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
268 return -1;
269 break;
270 case UDP4:
271 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
272 return -1;
273 break;
274 case UDP6:
275 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
276 return -1;
277 break;
278 case UNIX:
279 if (psutil_get_sockets("net.local.stream.pcblist") != 0)
280 return -1;
281 if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
282 return -1;
283 if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
284 return -1;
285 break;
286 case ALL:
287 if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
288 return -1;
289 if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
290 return -1;
291 if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
292 return -1;
293 if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
294 return -1;
295 if (psutil_get_sockets("net.local.stream.pcblist") != 0)
296 return -1;
297 if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
298 return -1;
299 if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
300 return -1;
301 break;
302 }
303
304 return 0;
305 }
306
307
308 /*
309 * Return system-wide connections (unless a pid != -1 is passed).
310 */
311 PyObject *
psutil_net_connections(PyObject * self,PyObject * args)312 psutil_net_connections(PyObject *self, PyObject *args) {
313 char laddr[PATH_MAX];
314 char raddr[PATH_MAX];
315 int32_t lport;
316 int32_t rport;
317 int32_t status;
318 pid_t pid;
319 PyObject *py_tuple = NULL;
320 PyObject *py_laddr = NULL;
321 PyObject *py_raddr = NULL;
322 PyObject *py_retlist = PyList_New(0);
323
324 if (py_retlist == NULL)
325 return NULL;
326
327 if (! PyArg_ParseTuple(args, "l", &pid))
328 return NULL;
329
330 psutil_kiflist_init();
331 psutil_kpcblist_init();
332 if (psutil_get_files() != 0)
333 goto error;
334 if (psutil_get_info(ALL) != 0)
335 goto error;
336
337 struct kif *k;
338 SLIST_FOREACH(k, &kihead, kifs) {
339 struct kpcb *kp;
340 if ((pid != -1) && (k->kif->ki_pid != (unsigned int)pid))
341 continue;
342 SLIST_FOREACH(kp, &kpcbhead, kpcbs) {
343 if (k->kif->ki_fdata != kp->kpcb->ki_sockaddr)
344 continue;
345
346 // IPv4 or IPv6
347 if ((kp->kpcb->ki_family == AF_INET) ||
348 (kp->kpcb->ki_family == AF_INET6)) {
349
350 if (kp->kpcb->ki_family == AF_INET) {
351 // IPv4
352 struct sockaddr_in *sin_src =
353 (struct sockaddr_in *)&kp->kpcb->ki_src;
354 struct sockaddr_in *sin_dst =
355 (struct sockaddr_in *)&kp->kpcb->ki_dst;
356 // source addr and port
357 inet_ntop(AF_INET, &sin_src->sin_addr, laddr,
358 sizeof(laddr));
359 lport = ntohs(sin_src->sin_port);
360 // remote addr and port
361 inet_ntop(AF_INET, &sin_dst->sin_addr, raddr,
362 sizeof(raddr));
363 rport = ntohs(sin_dst->sin_port);
364 }
365 else {
366 // IPv6
367 struct sockaddr_in6 *sin6_src =
368 (struct sockaddr_in6 *)&kp->kpcb->ki_src;
369 struct sockaddr_in6 *sin6_dst =
370 (struct sockaddr_in6 *)&kp->kpcb->ki_dst;
371 // local addr and port
372 inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr,
373 sizeof(laddr));
374 lport = ntohs(sin6_src->sin6_port);
375 // remote addr and port
376 inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr,
377 sizeof(raddr));
378 rport = ntohs(sin6_dst->sin6_port);
379 }
380
381 // status
382 if (kp->kpcb->ki_type == SOCK_STREAM)
383 status = kp->kpcb->ki_tstate;
384 else
385 status = PSUTIL_CONN_NONE;
386
387 // build addr tuple
388 py_laddr = Py_BuildValue("(si)", laddr, lport);
389 if (! py_laddr)
390 goto error;
391 if (rport != 0)
392 py_raddr = Py_BuildValue("(si)", raddr, rport);
393 else
394 py_raddr = Py_BuildValue("()");
395 if (! py_raddr)
396 goto error;
397 }
398 else if (kp->kpcb->ki_family == AF_UNIX) {
399 // UNIX sockets
400 struct sockaddr_un *sun_src =
401 (struct sockaddr_un *)&kp->kpcb->ki_src;
402 struct sockaddr_un *sun_dst =
403 (struct sockaddr_un *)&kp->kpcb->ki_dst;
404 strcpy(laddr, sun_src->sun_path);
405 strcpy(raddr, sun_dst->sun_path);
406 status = PSUTIL_CONN_NONE;
407 py_laddr = PyUnicode_DecodeFSDefault(laddr);
408 if (! py_laddr)
409 goto error;
410 py_raddr = PyUnicode_DecodeFSDefault(raddr);
411 if (! py_raddr)
412 goto error;
413 }
414 else {
415 continue;
416 }
417
418 // append tuple to list
419 py_tuple = Py_BuildValue(
420 "(iiiOOii)",
421 k->kif->ki_fd,
422 kp->kpcb->ki_family,
423 kp->kpcb->ki_type,
424 py_laddr,
425 py_raddr,
426 status,
427 k->kif->ki_pid);
428 if (! py_tuple)
429 goto error;
430 if (PyList_Append(py_retlist, py_tuple))
431 goto error;
432 Py_DECREF(py_laddr);
433 Py_DECREF(py_raddr);
434 Py_DECREF(py_tuple);
435 }
436 }
437
438 psutil_kiflist_clear();
439 psutil_kpcblist_clear();
440 return py_retlist;
441
442 error:
443 Py_XDECREF(py_tuple);
444 Py_XDECREF(py_laddr);
445 Py_XDECREF(py_raddr);
446 return 0;
447 }
448