nmsg  0.9.0
packet.c
1 /* packet nmsg message module */
2 
3 /*
4  * Copyright (c) 2013 by Farsight Security, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 /* Import. */
20 
21 #include "packet.pb-c.h"
22 
23 /* Exported via module context. */
24 
25 static nmsg_res
26 packet_pcap_init(void *clos, nmsg_pcap_t);
27 
28 static nmsg_res
29 packet_pkt_to_payload(void *clos, nmsg_pcap_t, nmsg_message_t *);
30 
31 /* Data. */
32 
33 struct nmsg_msgmod_field packet_fields[] = {
34  {
36  .name = "payload_type",
37  },
38  {
39  .type = nmsg_msgmod_ft_bytes,
40  .name = "payload",
41  },
42  NMSG_MSGMOD_FIELD_END
43 };
44 
45 /* Export. */
46 
47 struct nmsg_msgmod_plugin nmsg_msgmod_ctx = {
48  NMSG_MSGMOD_REQUIRED_INIT,
49  .vendor = NMSG_VENDOR_BASE,
50  .msgtype = { NMSG_VENDOR_BASE_PACKET_ID, NMSG_VENDOR_BASE_PACKET_NAME },
51  .pbdescr = &nmsg__base__packet__descriptor,
52  .fields = packet_fields,
53  .pkt_to_payload = packet_pkt_to_payload,
54  .pcap_init = packet_pcap_init
55 };
56 
57 static nmsg_res
58 packet_pcap_init(void *clos, nmsg_pcap_t pcap)
59 {
60  const char *dlt_name = NULL;
61  int dlt;
62 
63  dlt = nmsg_pcap_get_datalink(pcap);
64  dlt_name = pcap_datalink_val_to_name(dlt);
65  if (dlt_name == NULL)
66  dlt_name = "(unknown)";
67 
68  switch (dlt) {
69  case DLT_EN10MB:
70  case DLT_RAW:
71 #ifdef DLT_LINUX_SLL
72  case DLT_LINUX_SLL:
73 #endif
74  /* these types are fine, handle them */
75  break;
76  case DLT_NULL:
77  case DLT_LOOP:
78  /* these types require platform and runtime specific
79  * interpretation, so it is only safe to handle them on
80  * the original system which captured these frames */
81  if (nmsg_pcap_get_type(pcap) == nmsg_pcap_type_live)
82  return (nmsg_res_success);
83  if (nmsg_get_debug() >= 1) {
84  dlt_name = pcap_datalink_val_to_name(dlt);
85  fprintf(stderr, "%s: ERROR: Refusing to process packets from "
86  "a non-live pcap handle with datalink type %s\n",
87  __func__, dlt_name);
88  }
89  return (nmsg_res_failure);
90  default:
91  if (nmsg_get_debug() >= 1) {
92  fprintf(stderr, "%s: ERROR: Unable to open pcap handle with "
93  "datalink type %s\n", __func__, dlt_name);
94  }
95  return (nmsg_res_failure);
96  }
97 
98  if (nmsg_get_debug() >= 2)
99  fprintf(stderr, "%s: opening pcap handle with datalink type %s\n",
100  __func__, dlt_name);
101  return (nmsg_res_success);
102 }
103 
104 static nmsg_res
105 packet_load(nmsg_pcap_t pcap, Nmsg__Base__Packet *packet,
106  struct pcap_pkthdr *pkt_hdr,
107  const uint8_t *pkt)
108 {
109 #define advance_pkt(_pkt, _len, _sz) do { \
110  (_pkt) += (_sz); \
111  (_len) -= (_sz); \
112 } while (0)
113  size_t len = pkt_hdr->caplen;
114  uint32_t type = 0;
115 
116  /* only operate on complete packets */
117  if (pkt_hdr->caplen != pkt_hdr->len)
118  return (nmsg_res_again);
119 
120  packet->payload_type = NMSG__BASE__PACKET_TYPE__IP;
121 
122  switch (nmsg_pcap_get_datalink(pcap)) {
123  case DLT_EN10MB:
124  if (len < sizeof(struct nmsg_ethhdr))
125  return (nmsg_res_again);
126  advance_pkt(pkt, len, offsetof(struct nmsg_ethhdr, ether_type));
127  load_net16(pkt, &type);
128  advance_pkt(pkt, len, 2);
129  if (type == ETHERTYPE_VLAN) {
130  if (len < 4)
131  return (nmsg_res_again);
132  advance_pkt(pkt, len, 2);
133  load_net16(pkt, &type);
134  advance_pkt(pkt, len, 2);
135  }
136  if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6)
137  goto success;
138  return (nmsg_res_again);
139  break;
140  case DLT_RAW:
141  goto success;
142  break;
143 #ifdef DLT_LINUX_SLL
144  case DLT_LINUX_SLL:
145  if (len < 16)
146  return (nmsg_res_again);
147  advance_pkt(pkt, len, 14);
148  load_net16(pkt, &type);
149  advance_pkt(pkt, len, 2);
150  if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6)
151  goto success;
152  return (nmsg_res_again);
153  break;
154 #endif
155  case DLT_NULL:
156  if (len < sizeof(type))
157  return (nmsg_res_again);
158  memcpy(&type, pkt, sizeof(type));
159  advance_pkt(pkt, len, sizeof(type));
160  if (type == PF_INET || type == PF_INET6)
161  goto success;
162  return (nmsg_res_again);
163  break;
164  case DLT_LOOP:
165  if (len < sizeof(type))
166  return (nmsg_res_again);
167  load_net32(pkt, &type);
168  advance_pkt(pkt, len, sizeof(type));
169  if (type == PF_INET || type == PF_INET6)
170  goto success;
171  return (nmsg_res_again);
172  break;
173  default:
174  return (nmsg_res_failure);
175  }
176  return (nmsg_res_failure);
177 success:
178  packet->payload.data = (uint8_t *) pkt;
179  packet->payload.len = len;
180  return (nmsg_res_success);
181 #undef advance_pkt
182 }
183 
184 static nmsg_res
185 packet_pkt_to_payload(void *clos, nmsg_pcap_t pcap, nmsg_message_t *m)
186 {
187  Nmsg__Base__Packet packet;
188  ProtobufCBufferSimple sbuf;
189  nmsg_res res;
190  const uint8_t *pkt_data;
191  struct pcap_pkthdr *pkt_hdr;
192  struct timespec ts;
193  size_t buf_sz;
194 
195  res = nmsg_pcap_input_read_raw(pcap, &pkt_hdr, &pkt_data, &ts);
196  if (res != nmsg_res_success)
197  return (res);
198 
199  nmsg__base__packet__init(&packet);
200 
201  res = packet_load(pcap, &packet, pkt_hdr, pkt_data);
202  if (res != nmsg_res_success)
203  return (res);
204 
205  sbuf.base.append = protobuf_c_buffer_simple_append;
206  sbuf.len = 0;
207  sbuf.alloced = pkt_hdr->caplen + 64;
208  sbuf.data = malloc(sbuf.alloced);
209  if (sbuf.data == NULL)
210  return (nmsg_res_memfail);
211  sbuf.must_free_data = 1;
212 
213  buf_sz = nmsg__base__packet__pack_to_buffer(&packet, (ProtobufCBuffer *) &sbuf);
214  if (sbuf.data == NULL)
215  return (nmsg_res_memfail);
216 
217  *m = nmsg_message_from_raw_payload(NMSG_VENDOR_BASE_ID,
218  NMSG_VENDOR_BASE_PACKET_ID,
219  sbuf.data, buf_sz, &ts);
220  return (nmsg_res_success);
221 }
Structure exported by message modules to implement a new message type.
nmsg_res
nmsg result code
Definition: res.h:25
success
Definition: res.h:26
int nmsg_pcap_get_datalink(nmsg_pcap_t pcap)
Get the datalink type of the underlying pcap handle.
Definition: pcap_input.c:346
Protobuf enum.
Definition: msgmod.h:75
out of memory
Definition: res.h:29
caller should try again
Definition: res.h:35
nmsg_msgmod_type type
Module type.
Protobuf byte array.
Definition: msgmod.h:78
Structure mapping protocol buffer schema fields to nmsg_msgmod_field_type values for "transparent" mo...
generic failure
Definition: res.h:27
nmsg_pcap_type nmsg_pcap_get_type(nmsg_pcap_t pcap)
Get the type of the underlying pcap handle.
Definition: pcap_input.c:341
nmsg_msgmod_field_type type
Intended (nmsg) type of this protobuf field.
nmsg_message_t nmsg_message_from_raw_payload(unsigned vid, unsigned msgtype, uint8_t *data, size_t sz, const struct timespec *ts)
Initialize a new message object from an opaque payload blob.
int nmsg_get_debug(void)
Retrieve the current debug level.
Definition: nmsg.c:71
nmsg_res nmsg_pcap_input_read_raw(nmsg_pcap_t pcap, struct pcap_pkthdr **pkt_hdr, const uint8_t **pkt_data, struct timespec *ts)
Read a raw packet from an nmsg_pcap_t input.
Definition: pcap_input.c:100