Branch data Line data Source code
1 : : #include <linux/if_packet.h>
2 : : #include <sys/socket.h>
3 : : #include <linux/netlink.h>
4 : : #include <linux/rtnetlink.h>
5 : : #include <unistd.h>
6 : : #include <string.h>
7 : : #include "crtools.h"
8 : : #include "types.h"
9 : : #include "files.h"
10 : : #include "sockets.h"
11 : : #include "libnetlink.h"
12 : : #include "sk-packet.h"
13 : : #include "packet_diag.h"
14 : :
15 : : #include "protobuf.h"
16 : : #include "protobuf/packet-sock.pb-c.h"
17 : : #include "protobuf/fdinfo.pb-c.h"
18 : :
19 : : struct packet_sock_info {
20 : : PacketSockEntry *pse;
21 : : struct file_desc d;
22 : : };
23 : :
24 : : struct packet_mreq_max {
25 : : int mr_ifindex;
26 : : unsigned short mr_type;
27 : : unsigned short mr_alen;
28 : : unsigned char mr_address[MAX_ADDR_LEN];
29 : : };
30 : :
31 : : struct packet_sock_desc {
32 : : struct socket_desc sd;
33 : : unsigned int file_id;
34 : : unsigned int type;
35 : : unsigned short proto;
36 : : struct packet_diag_info nli;
37 : : int mreq_n;
38 : : struct packet_diag_mclist *mreqs;
39 : : unsigned int fanout;
40 : : struct packet_diag_ring *rx, *tx;
41 : : };
42 : :
43 : : #define NO_FANOUT ((unsigned int)-1)
44 : :
45 : 0 : void show_packetsk(int fd, struct cr_options *o)
46 : : {
47 : 0 : pb_show_plain_pretty(fd, PB_PACKETSK, "5:%d");
48 : 0 : }
49 : :
50 : 4 : static int dump_mreqs(PacketSockEntry *psk, struct packet_sock_desc *sd)
51 : : {
52 : : int i;
53 : :
54 [ + - ]: 4 : if (!sd->mreq_n)
55 : : return 0;
56 : :
57 : 4 : pr_debug("\tdumping %d mreqs\n", sd->mreq_n);
58 [ - + ]: 4 : psk->mclist = xmalloc(sd->mreq_n * sizeof(psk->mclist[0]));
59 [ + - ]: 4 : if (!psk->mclist)
60 : : return -1;
61 : :
62 [ + + ]: 8 : for (i = 0; i < sd->mreq_n; i++) {
63 : 4 : struct packet_diag_mclist *m = &sd->mreqs[i];
64 : : PacketMclist *im;
65 : :
66 [ - + ]: 4 : if (m->pdmc_count != 1) {
67 : 0 : pr_err("Multiple MC membership not supported (but can be)\n");
68 : : goto err;
69 : : }
70 : :
71 : 4 : pr_debug("\tmr%d: idx %d type %d\n", i,
72 : : m->pdmc_index, m->pdmc_type);
73 : :
74 [ - + ]: 4 : im = xmalloc(sizeof(*im));
75 [ + - ]: 4 : if (!im)
76 : : goto err;
77 : :
78 : 4 : packet_mclist__init(im);
79 : 4 : psk->mclist[i] = im;
80 : 4 : psk->n_mclist++;
81 : :
82 : 4 : im->index = m->pdmc_index;
83 : 4 : im->type = m->pdmc_type;
84 : :
85 [ + - + ]: 4 : switch (m->pdmc_type) {
86 : : case PACKET_MR_MULTICAST:
87 : : case PACKET_MR_UNICAST:
88 : 2 : im->addr.len = m->pdmc_alen;
89 [ - + ]: 2 : im->addr.data = xmalloc(m->pdmc_alen);
90 [ + - ]: 2 : if (!im->addr.data)
91 : : goto err;
92 : :
93 : 2 : memcpy(im->addr.data, m->pdmc_addr, m->pdmc_alen);
94 : : break;
95 : : case PACKET_MR_PROMISC:
96 : : case PACKET_MR_ALLMULTI:
97 : : break;
98 : : default:
99 : 0 : pr_err("Unknown mc membership type %d\n", m->pdmc_type);
100 : : goto err;
101 : : }
102 : : }
103 : :
104 : : return 0;
105 : : err:
106 : : return -1;
107 : : }
108 : :
109 : 4 : static PacketRing *dump_ring(struct packet_diag_ring *dr)
110 : : {
111 : : PacketRing *ring;
112 : :
113 [ - + ]: 4 : ring = xmalloc(sizeof(*ring));
114 [ + - ]: 4 : if (!ring)
115 : : return NULL;
116 : :
117 : 4 : packet_ring__init(ring);
118 : :
119 : 4 : ring->block_size = dr->pdr_block_size;
120 : 4 : ring->block_nr = dr->pdr_block_nr;
121 : 4 : ring->frame_size = dr->pdr_frame_size;
122 : 4 : ring->frame_nr = dr->pdr_frame_nr;
123 : 4 : ring->retire_tmo = dr->pdr_retire_tmo;
124 : 4 : ring->sizeof_priv = dr->pdr_sizeof_priv;
125 : 4 : ring->features = dr->pdr_features;
126 : :
127 : 4 : return ring;
128 : : }
129 : :
130 : 4 : static int dump_rings(PacketSockEntry *psk, struct packet_sock_desc *sd)
131 : : {
132 [ + + ]: 4 : if (sd->rx) {
133 : 2 : psk->rx_ring = dump_ring(sd->rx);
134 [ + - ]: 2 : if (!psk->rx_ring)
135 : : return -1;
136 : : }
137 : :
138 [ + + ]: 4 : if (sd->tx) {
139 : 2 : psk->tx_ring = dump_ring(sd->tx);
140 [ + - ]: 4 : if (!psk->tx_ring)
141 : : return -1;
142 : : }
143 : :
144 : : return 0;
145 : : }
146 : :
147 : 4 : static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
148 : : {
149 : 4 : PacketSockEntry psk = PACKET_SOCK_ENTRY__INIT;
150 : 4 : SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
151 : : struct packet_sock_desc *sd;
152 : : int i, ret;
153 : :
154 : 4 : sd = (struct packet_sock_desc *)lookup_socket(p->stat.st_ino, PF_PACKET);
155 : : if (sd < 0)
156 : : return -1;
157 : :
158 : 4 : pr_info("Dumping packet socket fd %d id %#x\n", lfd, id);
159 [ - + ]: 4 : BUG_ON(sd->sd.already_dumped);
160 : 4 : sd->sd.already_dumped = 1;
161 : :
162 : 4 : psk.id = sd->file_id = id;
163 : 4 : psk.type = sd->type;
164 : 4 : psk.flags = p->flags;
165 : 4 : psk.fown = (FownEntry *)&p->fown;
166 : 4 : psk.opts = &skopts;
167 : :
168 [ + - ]: 4 : if (dump_socket_opts(lfd, &skopts))
169 : : return -1;
170 : :
171 : 4 : psk.protocol = sd->proto;
172 : 4 : psk.ifindex = sd->nli.pdi_index;
173 : 4 : psk.version = sd->nli.pdi_version;
174 : 4 : psk.reserve = sd->nli.pdi_reserve;
175 : 4 : psk.timestamp = sd->nli.pdi_tstamp;
176 : 4 : psk.copy_thresh = sd->nli.pdi_copy_thresh;
177 : 4 : psk.aux_data = (sd->nli.pdi_flags & PDI_AUXDATA ? true : false);
178 : 4 : psk.orig_dev = (sd->nli.pdi_flags & PDI_ORIGDEV ? true : false);
179 : 4 : psk.vnet_hdr = (sd->nli.pdi_flags & PDI_VNETHDR ? true : false);
180 : 4 : psk.loss = (sd->nli.pdi_flags & PDI_LOSS ? true : false);
181 : :
182 : 4 : ret = dump_mreqs(&psk, sd);
183 [ + - ]: 4 : if (ret)
184 : : goto out;
185 : :
186 [ + + ]: 4 : if (sd->fanout != NO_FANOUT) {
187 : 2 : psk.has_fanout = true;
188 : 2 : psk.fanout = sd->fanout;
189 : : }
190 : :
191 : 4 : ret = dump_rings(&psk, sd);
192 [ + - ]: 4 : if (ret)
193 : : goto out;
194 : :
195 : 4 : ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_PACKETSK), &psk, PB_PACKETSK);
196 : : out:
197 : 4 : release_skopts(&skopts);
198 [ + + ]: 4 : xfree(psk.rx_ring);
199 [ + + ]: 4 : xfree(psk.tx_ring);
200 [ + + ]: 8 : for (i = 0; i < psk.n_mclist; i++)
201 [ + + ]: 4 : xfree(psk.mclist[i]->addr.data);
202 [ + - ]: 4 : xfree(psk.mclist);
203 : : return ret;
204 : : }
205 : :
206 : : static const struct fdtype_ops packet_dump_ops = {
207 : : .type = FD_TYPES__PACKETSK,
208 : : .dump = dump_one_packet_fd,
209 : : };
210 : :
211 : 4 : int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds)
212 : : {
213 : 4 : return do_dump_gen_file(p, lfd, &packet_dump_ops, fds);
214 : : }
215 : :
216 : 0 : int dump_socket_map(struct vma_area *vma)
217 : : {
218 : : struct packet_sock_desc *sd;
219 : :
220 : 0 : sd = (struct packet_sock_desc *)lookup_socket(vma->vm_socket_id, PF_PACKET);
221 [ # # ]: 0 : if (!sd) {
222 : 0 : pr_err("Can't find packet socket %u to mmap\n", vma->vm_socket_id);
223 : 0 : return -1;
224 : : }
225 : :
226 [ # # ]: 0 : if (!sd->file_id) {
227 : 0 : pr_err("Mmap-ed socket %u not open\n", vma->vm_socket_id);
228 : 0 : return -1;
229 : : }
230 : :
231 : 0 : pr_info("Dumping socket map %x -> %lx\n", sd->file_id, vma->vma.start);
232 : 0 : vma->vma.shmid = sd->file_id;
233 : 0 : return 0;
234 : : }
235 : :
236 : 95 : static int packet_save_mreqs(struct packet_sock_desc *sd, struct rtattr *mc)
237 : : {
238 : 95 : sd->mreq_n = RTA_PAYLOAD(mc) / sizeof(struct packet_diag_mclist);
239 : 95 : pr_debug("\tGot %d mreqs\n", sd->mreq_n);
240 [ - + ]: 95 : sd->mreqs = xmalloc(RTA_PAYLOAD(mc));
241 [ + - ]: 95 : if (!sd->mreqs)
242 : : return -1;
243 : :
244 : 95 : memcpy(sd->mreqs, RTA_DATA(mc), RTA_PAYLOAD(mc));
245 : : return 0;
246 : : }
247 : :
248 : 95 : int packet_receive_one(struct nlmsghdr *hdr, void *arg)
249 : : {
250 : : struct packet_diag_msg *m;
251 : : struct rtattr *tb[PACKET_DIAG_MAX + 1];
252 : : struct packet_sock_desc *sd;
253 : :
254 : 95 : m = NLMSG_DATA(hdr);
255 : 95 : parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(m + 1),
256 : 95 : hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
257 : 95 : pr_info("Collect packet sock %u %u\n", m->pdiag_ino, (unsigned int)m->pdiag_num);
258 : :
259 [ - + ]: 95 : if (!tb[PACKET_DIAG_INFO]) {
260 : 0 : pr_err("No packet sock info in nlm\n");
261 : : return -1;
262 : : }
263 : :
264 [ - + ]: 95 : if (!tb[PACKET_DIAG_MCLIST]) {
265 : 0 : pr_err("No packet sock mclist in nlm\n");
266 : : return -1;
267 : : }
268 : :
269 [ - + ]: 95 : sd = xmalloc(sizeof(*sd));
270 [ + - ]: 95 : if (!sd)
271 : : return -1;
272 : :
273 : 95 : sd->file_id = 0;
274 : 95 : sd->type = m->pdiag_type;
275 [ - + ]: 95 : sd->proto = htons(m->pdiag_num);
276 : 95 : memcpy(&sd->nli, RTA_DATA(tb[PACKET_DIAG_INFO]), sizeof(sd->nli));
277 : :
278 [ + - ]: 95 : if (packet_save_mreqs(sd, tb[PACKET_DIAG_MCLIST]))
279 : : return -1;
280 : :
281 [ + + ]: 95 : if (tb[PACKET_DIAG_FANOUT])
282 : 2 : sd->fanout = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_FANOUT]);
283 : : else
284 : 93 : sd->fanout = NO_FANOUT;
285 : :
286 [ + + ]: 95 : if (tb[PACKET_DIAG_RX_RING]) {
287 [ - + ]: 2 : sd->rx = xmalloc(sizeof(*sd->rx));
288 : 2 : memcpy(sd->rx, RTA_DATA(tb[PACKET_DIAG_RX_RING]), sizeof(*sd->rx));
289 : : } else
290 : 93 : sd->rx = NULL;
291 : :
292 [ + + ]: 95 : if (tb[PACKET_DIAG_TX_RING]) {
293 [ - + ]: 2 : sd->tx = xmalloc(sizeof(*sd->tx));
294 : 2 : memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx));
295 : : } else
296 : 93 : sd->tx = NULL;
297 : :
298 : 95 : return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd);
299 : : }
300 : :
301 : 0 : int get_socket_fd(int pid, VmaEntry *vma)
302 : : {
303 : : struct file_desc *fd;
304 : : struct fdinfo_list_entry *le;
305 : :
306 : 0 : pr_info("Getting packet socket fd for %d:%x\n",
307 : : pid, (int)vma->shmid);
308 : 0 : fd = find_file_desc_raw(FD_TYPES__PACKETSK, vma->shmid);
309 [ # # ]: 0 : if (!fd) {
310 : 0 : pr_err("No packet socket %x\n", (int)vma->shmid);
311 : 0 : return -1;
312 : : }
313 : :
314 [ # # ]: 0 : list_for_each_entry(le, &fd->fd_info_head, desc_list)
315 [ # # ]: 0 : if (le->pid == pid) {
316 : : int fd;
317 : :
318 : : /*
319 : : * Restorer will close the mmap-ed fd
320 : : */
321 : :
322 : 0 : fd = dup(le->fe->fd);
323 [ # # ]: 0 : if (!fd) {
324 : 0 : pr_perror("Can't dup packet sk");
325 : 0 : return -1;
326 : : }
327 : :
328 : : return fd;
329 : : }
330 : :
331 : 0 : pr_err("No open packet socket %x by %d\n", (int)vma->shmid, pid);
332 : 0 : return -1;
333 : : }
334 : :
335 : 4 : static int restore_mreqs(int sk, PacketSockEntry *pse)
336 : : {
337 : : int i;
338 : :
339 [ + + ]: 8 : for (i = 0; i < pse->n_mclist; i++) {
340 : : PacketMclist *ml;
341 : : struct packet_mreq_max mreq;
342 : :
343 : 4 : ml = pse->mclist[i];
344 : 4 : pr_info("Restoring mreq type %d\n", ml->type);
345 : :
346 [ - + ]: 4 : if (ml->addr.len > sizeof(mreq.mr_address)) {
347 : 0 : pr_err("To big mcaddr %lu\n", ml->addr.len);
348 : : return -1;
349 : : }
350 : :
351 : 4 : mreq.mr_ifindex = ml->index;
352 : 4 : mreq.mr_type = ml->type;
353 : 4 : mreq.mr_alen = ml->addr.len;
354 : 4 : memcpy(mreq.mr_address, ml->addr.data, ml->addr.len);
355 : :
356 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq))
357 : : return -1;
358 : : }
359 : :
360 : : return 0;
361 : : }
362 : :
363 : 8 : static int restore_ring(int sk, int type, PacketRing *ring)
364 : : {
365 : : struct tpacket_req3 req;
366 : :
367 [ + + ]: 8 : if (!ring)
368 : : return 0;
369 : :
370 : 4 : pr_debug("\tRestoring %d ring\n", type);
371 : :
372 : 4 : req.tp_block_size = ring->block_size;
373 : 4 : req.tp_block_nr = ring->block_nr;
374 : 4 : req.tp_frame_size = ring->frame_size;
375 : 4 : req.tp_frame_nr = ring->frame_nr;
376 : 4 : req.tp_retire_blk_tov = ring->retire_tmo;
377 : 4 : req.tp_sizeof_priv = ring->sizeof_priv;
378 : 4 : req.tp_feature_req_word = ring->features;
379 : :
380 : 8 : return restore_opt(sk, SOL_PACKET, type, &req);
381 : : }
382 : :
383 : 4 : static int restore_rings(int sk, PacketSockEntry *psk)
384 : : {
385 [ + - ]: 4 : if (restore_ring(sk, PACKET_RX_RING, psk->rx_ring))
386 : : return -1;
387 : :
388 [ + - ]: 4 : if (restore_ring(sk, PACKET_TX_RING, psk->tx_ring))
389 : : return -1;
390 : :
391 : : return 0;
392 : : }
393 : :
394 : 4 : static int open_packet_sk(struct file_desc *d)
395 : : {
396 : : struct packet_sock_info *psi;
397 : : PacketSockEntry *pse;
398 : : struct sockaddr_ll addr;
399 : : int sk, yes;
400 : :
401 : 4 : psi = container_of(d, struct packet_sock_info, d);
402 : 4 : pse = psi->pse;
403 : :
404 : 4 : pr_info("Opening packet socket id %#x\n", pse->id);
405 : :
406 : 4 : sk = socket(PF_PACKET, pse->type, pse->protocol);
407 [ - + ]: 4 : if (sk < 0) {
408 : 0 : pr_perror("Can't create packet sock");
409 : 0 : goto err;
410 : : }
411 : :
412 : 4 : memset(&addr, 0, sizeof(addr));
413 : 4 : addr.sll_family = AF_PACKET;
414 : 4 : addr.sll_ifindex = pse->ifindex;
415 : :
416 [ - + ]: 4 : if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
417 : 0 : pr_perror("Can't bind packet socket");
418 : 0 : goto err_cl;
419 : : }
420 : :
421 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_VERSION, &pse->version))
422 : : goto err_cl;
423 : :
424 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_RESERVE, &pse->reserve))
425 : : goto err_cl;
426 : :
427 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_TIMESTAMP, &pse->timestamp))
428 : : goto err_cl;
429 : :
430 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_COPY_THRESH, &pse->copy_thresh))
431 : : goto err_cl;
432 : :
433 [ + + ]: 4 : if (pse->aux_data) {
434 : 2 : yes = 1;
435 [ + - ]: 2 : if (restore_opt(sk, SOL_PACKET, PACKET_AUXDATA, &yes))
436 : : goto err_cl;
437 : : }
438 : :
439 [ + + ]: 4 : if (pse->orig_dev) {
440 : 2 : yes = 1;
441 [ + - ]: 2 : if (restore_opt(sk, SOL_PACKET, PACKET_ORIGDEV, &yes))
442 : : goto err_cl;
443 : : }
444 : :
445 [ - + ]: 4 : if (pse->vnet_hdr) {
446 : 0 : yes = 1;
447 [ # # ]: 0 : if (restore_opt(sk, SOL_PACKET, PACKET_VNET_HDR, &yes))
448 : : goto err_cl;
449 : : }
450 : :
451 [ - + ]: 4 : if (pse->loss) {
452 : 0 : yes = 1;
453 [ # # ]: 0 : if (restore_opt(sk, SOL_PACKET, PACKET_LOSS, &yes))
454 : : goto err_cl;
455 : : }
456 : :
457 [ + - ]: 4 : if (restore_mreqs(sk, pse))
458 : : goto err_cl;
459 : :
460 [ + - ]: 4 : if (restore_rings(sk, pse))
461 : : goto err_cl;
462 : :
463 [ + + ]: 4 : if (pse->has_fanout) {
464 : 2 : pr_info("Restoring fanout %x\n", pse->fanout);
465 [ + - ]: 2 : if (restore_opt(sk, SOL_PACKET, PACKET_FANOUT, &pse->fanout))
466 : : goto err_cl;
467 : : }
468 : :
469 [ + - ]: 4 : if (rst_file_params(sk, pse->fown, pse->flags))
470 : : goto err_cl;
471 : :
472 [ - + ]: 4 : if (restore_socket_opts(sk, pse->opts))
473 : : goto err_cl;
474 : :
475 : : return sk;
476 : :
477 : : err_cl:
478 : 4 : close(sk);
479 : : err:
480 : : return -1;
481 : : }
482 : :
483 : : static struct file_desc_ops packet_sock_desc_ops = {
484 : : .type = FD_TYPES__PACKETSK,
485 : : .open = open_packet_sk,
486 : : };
487 : :
488 : 6 : static int collect_one_packet_sk(void *o, ProtobufCMessage *base)
489 : : {
490 : 6 : struct packet_sock_info *si = o;
491 : :
492 : 6 : si->pse = pb_msg(base, PacketSockEntry);
493 : 6 : file_desc_add(&si->d, si->pse->id, &packet_sock_desc_ops);
494 : :
495 : 6 : return 0;
496 : : }
497 : :
498 : 355 : int collect_packet_sockets(void)
499 : : {
500 : 355 : return collect_image(CR_FD_PACKETSK, PB_PACKETSK,
501 : : sizeof(struct packet_sock_info), collect_one_packet_sk);
502 : 222 : }
|