1 /*
2 * Copyright (c) 2017, Arnon Yaari
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 /* Baded on code from lsof:
9 * http://www.ibm.com/developerworks/aix/library/au-lsof.html
10 * - dialects/aix/dproc.c:gather_proc_info
11 * - lib/prfp.c:process_file
12 * - dialects/aix/dsock.c:process_socket
13 * - dialects/aix/dproc.c:get_kernel_access
14 */
15
16 #include <Python.h>
17 #include <stdlib.h>
18 #include <fcntl.h>
19 #define _KERNEL
20 #include <sys/file.h>
21 #undef _KERNEL
22 #include <sys/types.h>
23 #include <sys/core.h>
24 #include <sys/domain.h>
25 #include <sys/un.h>
26 #include <netinet/in_pcb.h>
27 #include <arpa/inet.h>
28
29 #include "../../_psutil_common.h"
30 #include "net_kernel_structs.h"
31 #include "net_connections.h"
32 #include "common.h"
33
34 #define NO_SOCKET (PyObject *)(-1)
35
36 static int
read_unp_addr(int Kd,KA_T unp_addr,char * buf,size_t buflen)37 read_unp_addr(
38 int Kd,
39 KA_T unp_addr,
40 char *buf,
41 size_t buflen
42 ) {
43 struct sockaddr_un *ua = (struct sockaddr_un *)NULL;
44 struct sockaddr_un un;
45 struct mbuf64 mb;
46 int uo;
47
48 if (psutil_kread(Kd, unp_addr, (char *)&mb, sizeof(mb))) {
49 return 1;
50 }
51
52 uo = (int)(mb.m_hdr.mh_data - unp_addr);
53 if ((uo + sizeof(struct sockaddr)) <= sizeof(mb))
54 ua = (struct sockaddr_un *)((char *)&mb + uo);
55 else {
56 if (psutil_kread(Kd, (KA_T)mb.m_hdr.mh_data,
57 (char *)&un, sizeof(un))) {
58 return 1;
59 }
60 ua = &un;
61 }
62 if (ua && ua->sun_path[0]) {
63 if (mb.m_len > sizeof(struct sockaddr_un))
64 mb.m_len = sizeof(struct sockaddr_un);
65 *((char *)ua + mb.m_len - 1) = '\0';
66 snprintf(buf, buflen, "%s", ua->sun_path);
67 }
68 return 0;
69 }
70
71 static PyObject *
process_file(int Kd,pid32_t pid,int fd,KA_T fp)72 process_file(int Kd, pid32_t pid, int fd, KA_T fp) {
73 struct file64 f;
74 struct socket64 s;
75 struct protosw64 p;
76 struct domain d;
77 struct inpcb64 inp;
78 int fam;
79 struct tcpcb64 t;
80 int state = PSUTIL_CONN_NONE;
81 unsigned char *laddr = (unsigned char *)NULL;
82 unsigned char *raddr = (unsigned char *)NULL;
83 int rport, lport;
84 char laddr_str[INET6_ADDRSTRLEN];
85 char raddr_str[INET6_ADDRSTRLEN];
86 struct unpcb64 unp;
87 char unix_laddr_str[PATH_MAX] = { 0 };
88 char unix_raddr_str[PATH_MAX] = { 0 };
89
90 /* Read file structure */
91 if (psutil_kread(Kd, fp, (char *)&f, sizeof(f))) {
92 return NULL;
93 }
94 if (!f.f_count || f.f_type != DTYPE_SOCKET) {
95 return NO_SOCKET;
96 }
97
98 if (psutil_kread(Kd, (KA_T) f.f_data, (char *) &s, sizeof(s))) {
99 return NULL;
100 }
101
102 if (!s.so_type) {
103 return NO_SOCKET;
104 }
105
106 if (!s.so_proto) {
107 PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol handle");
108 return NULL;
109 }
110 if (psutil_kread(Kd, (KA_T)s.so_proto, (char *)&p, sizeof(p))) {
111 return NULL;
112 }
113
114 if (!p.pr_domain) {
115 PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol domain");
116 return NULL;
117 }
118 if (psutil_kread(Kd, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
119 return NULL;
120 }
121
122 fam = d.dom_family;
123 if (fam == AF_INET || fam == AF_INET6) {
124 /* Read protocol control block */
125 if (!s.so_pcb) {
126 PyErr_SetString(PyExc_RuntimeError, "invalid socket PCB");
127 return NULL;
128 }
129 if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *) &inp, sizeof(inp))) {
130 return NULL;
131 }
132
133 if (p.pr_protocol == IPPROTO_TCP) {
134 /* If this is a TCP socket, read its control block */
135 if (inp.inp_ppcb
136 && !psutil_kread(Kd, (KA_T)inp.inp_ppcb,
137 (char *)&t, sizeof(t)))
138 state = t.t_state;
139 }
140
141 if (fam == AF_INET6) {
142 laddr = (unsigned char *)&inp.inp_laddr6;
143 if (!IN6_IS_ADDR_UNSPECIFIED(&inp.inp_faddr6)) {
144 raddr = (unsigned char *)&inp.inp_faddr6;
145 rport = (int)ntohs(inp.inp_fport);
146 }
147 }
148 if (fam == AF_INET) {
149 laddr = (unsigned char *)&inp.inp_laddr;
150 if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
151 raddr = (unsigned char *)&inp.inp_faddr;
152 rport = (int)ntohs(inp.inp_fport);
153 }
154 }
155 lport = (int)ntohs(inp.inp_lport);
156
157 inet_ntop(fam, laddr, laddr_str, sizeof(laddr_str));
158
159 if (raddr != NULL) {
160 inet_ntop(fam, raddr, raddr_str, sizeof(raddr_str));
161 return Py_BuildValue("(iii(si)(si)ii)", fd, fam,
162 s.so_type, laddr_str, lport, raddr_str,
163 rport, state, pid);
164 }
165 else {
166 return Py_BuildValue("(iii(si)()ii)", fd, fam,
167 s.so_type, laddr_str, lport, state,
168 pid);
169 }
170 }
171
172
173 if (fam == AF_UNIX) {
174 if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *)&unp, sizeof(unp))) {
175 return NULL;
176 }
177 if ((KA_T) f.f_data != (KA_T) unp.unp_socket) {
178 PyErr_SetString(PyExc_RuntimeError, "unp_socket mismatch");
179 return NULL;
180 }
181
182 if (unp.unp_addr) {
183 if (read_unp_addr(Kd, unp.unp_addr, unix_laddr_str,
184 sizeof(unix_laddr_str))) {
185 return NULL;
186 }
187 }
188
189 if (unp.unp_conn) {
190 if (psutil_kread(Kd, (KA_T) unp.unp_conn, (char *)&unp,
191 sizeof(unp))) {
192 return NULL;
193 }
194 if (read_unp_addr(Kd, unp.unp_addr, unix_raddr_str,
195 sizeof(unix_raddr_str))) {
196 return NULL;
197 }
198 }
199
200 return Py_BuildValue("(iiissii)", fd, d.dom_family,
201 s.so_type, unix_laddr_str, unix_raddr_str, PSUTIL_CONN_NONE,
202 pid);
203 }
204 return NO_SOCKET;
205 }
206
207 PyObject *
psutil_net_connections(PyObject * self,PyObject * args)208 psutil_net_connections(PyObject *self, PyObject *args) {
209 PyObject *py_retlist = PyList_New(0);
210 PyObject *py_tuple = NULL;
211 KA_T fp;
212 int Kd = -1;
213 int i, np;
214 struct procentry64 *p;
215 struct fdsinfo64 *fds = (struct fdsinfo64 *)NULL;
216 pid32_t requested_pid;
217 pid32_t pid;
218 struct procentry64 *processes = (struct procentry64 *)NULL;
219 /* the process table */
220
221 if (py_retlist == NULL)
222 goto error;
223 if (! PyArg_ParseTuple(args, "i", &requested_pid))
224 goto error;
225
226 Kd = open(KMEM, O_RDONLY, 0);
227 if (Kd < 0) {
228 PyErr_SetFromErrnoWithFilename(PyExc_OSError, KMEM);
229 goto error;
230 }
231
232 processes = psutil_read_process_table(&np);
233 if (!processes)
234 goto error;
235
236 /* Loop through processes */
237 for (p = processes; np > 0; np--, p++) {
238 pid = p->pi_pid;
239 if (requested_pid != -1 && requested_pid != pid)
240 continue;
241 if (p->pi_state == 0 || p->pi_state == SZOMB)
242 continue;
243
244 if (!fds) {
245 fds = (struct fdsinfo64 *)malloc((size_t)FDSINFOSIZE);
246 if (!fds) {
247 PyErr_NoMemory();
248 goto error;
249 }
250 }
251 if (getprocs64((struct procentry64 *)NULL, PROCSIZE, fds, FDSINFOSIZE,
252 &pid, 1)
253 != 1)
254 continue;
255
256 /* loop over file descriptors */
257 for (i = 0; i < p->pi_maxofile; i++) {
258 fp = (KA_T)fds->pi_ufd[i].fp;
259 if (fp) {
260 py_tuple = process_file(Kd, p->pi_pid, i, fp);
261 if (py_tuple == NULL)
262 goto error;
263 if (py_tuple != NO_SOCKET) {
264 if (PyList_Append(py_retlist, py_tuple))
265 goto error;
266 Py_DECREF(py_tuple);
267 }
268 }
269 }
270 }
271 close(Kd);
272 free(processes);
273 if (fds != NULL)
274 free(fds);
275 return py_retlist;
276
277 error:
278 Py_XDECREF(py_tuple);
279 Py_DECREF(py_retlist);
280 if (Kd > 0)
281 close(Kd);
282 if (processes != NULL)
283 free(processes);
284 if (fds != NULL)
285 free(fds);
286 return NULL;
287 }
288