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