nmsg  0.14.0
base/ipreasm.h
1 #ifndef NMSG_BASE_IPREASM_H
2 #define NMSG_BASE_IPREASM_H
3 
4 /*
5  * Copyright (c) 2007 Jan Andres <jandres@gmx.net>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  */
11 
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <time.h>
15 
16 struct reasm_ip;
17 
18 enum entry_state {
19  STATE_ACTIVE,
20  STATE_INVALID
21 };
22 
23 enum reasm_proto {
24  PROTO_IPV4,
25  PROTO_IPV6
26 };
27 
28 /*
29  * This tuple uniquely identifies all fragments belonging to
30  * the same IPv4 packet.
31  */
32 struct reasm_id_ipv4 {
33  uint8_t ip_src[4];
34  uint8_t ip_dst[4];
35  uint16_t ip_id;
36  uint8_t ip_proto;
37 };
38 
39 /*
40  * Same for IPv6.
41  */
42 struct reasm_id_ipv6 {
43  uint8_t ip_src[16];
44  uint8_t ip_dst[16];
45  uint32_t ip_id;
46 };
47 
48 union reasm_id {
49  struct reasm_id_ipv4 ipv4;
50  struct reasm_id_ipv6 ipv6;
51 };
52 
54  struct timespec ts;
55  unsigned len; /* payload length of this fragment */
56  unsigned offset; /* offset of this fragment into the payload of the reassembled packet */
57  unsigned data_offset; /* offset to the data pointer where payload starts */
58  unsigned last_nxt;
59  unsigned ip6f_nxt;
60  uint8_t *data; /* payload starts at data + data_offset */
61  struct reasm_frag_entry *next;
62 };
63 
64 /*
65  * Reception of a complete packet is detected by counting the number
66  * of "holes" that remain between the cached fragments. A hole is
67  * assumed to exist at the upper end of the packet until the final
68  * fragment has been received. When the number of holes drops to 0,
69  * all fragments have been received and the packet can be reassembled.
70  */
72  union reasm_id id;
73  unsigned len;
74  unsigned holes;
75  unsigned frag_count;
76  unsigned hash;
77  struct timespec timeout;
78  enum entry_state state;
79  enum reasm_proto protocol;
80  struct reasm_frag_entry *frags;
81  struct reasm_ip_entry *prev, *next;
82  struct reasm_ip_entry *time_prev, *time_next;
83 };
84 
85 /*
86  * Functions to create and destroy the reassembly environment.
87  */
88 struct reasm_ip *reasm_ip_new(void);
89 void reasm_ip_free(struct reasm_ip *reasm);
90 
91 /*
92  * This is the main packet processing function. It inputs one packet,
93  * and MAY output one packet in turn. If the input was not a fragment,
94  * no output is generated, and false is returned. If the input was a
95  * fragment, true is returned.
96  * The unsigned pointed to by output_len should initially be set to the
97  * size of the buffer behind out_packet. On return, it will be set to
98  * the length of the packet returned, or 0 if no packet was returned
99  * (this will happen if a fragment is recognized, but reassembly of the
100  * corresponding packet has not completed yet).
101  */
102 bool reasm_ip_next(struct reasm_ip *reasm, const uint8_t *packet, unsigned len,
103  const struct timespec *timestamp, struct reasm_ip_entry **out_entry);
104 
105 /*
106  * Create fragment structure from an IPv4 or IPv6 packet. Returns NULL
107  * if the input is not a fragment.
108  *
109  * \param[in] packet
110  * \param[in] len
111  * \param[in] ts
112  * \param[out] protocol
113  * \param[out] id
114  * \param[out] hash
115  * \param[out] last_frag
116  */
117 struct reasm_frag_entry *reasm_parse_packet(const uint8_t *packet, unsigned len,
118  const struct timespec *ts,
119  enum reasm_proto *protocol, union reasm_id *id,
120  unsigned *hash, bool *last_frag);
121 
122 /*
123  * Set the timeout after which a noncompleted reassembly expires.
124  */
125 bool reasm_ip_set_timeout(struct reasm_ip *reasm, const struct timespec *timeout);
126 
127 /*
128  * Query certain information about the current state.
129  */
130 unsigned reasm_ip_waiting(const struct reasm_ip *reasm);
131 unsigned reasm_ip_max_waiting(const struct reasm_ip *reasm);
132 unsigned reasm_ip_timed_out(const struct reasm_ip *reasm);
133 unsigned reasm_ip_dropped_frags(const struct reasm_ip *reasm);
134 
135 /*
136  * Is the entry complete, ready for reassembly?
137  */
138 bool reasm_is_complete(struct reasm_ip_entry *entry);
139 
140 /*
141  * Create the reassembled packet.
142  *
143  * \param[in] entry
144  * \param[out] out_packet
145  * \param[in,out] output_len
146  */
147 void reasm_assemble(struct reasm_ip_entry *entry,
148  uint8_t *out_packet, size_t *output_len);
149 
150 /*
151  * Insert a new fragment to the correct position in the list of fragments.
152  * Check for fragment overlap and other error conditions.
153  */
154 bool reasm_add_fragment(struct reasm_ip_entry *entry,
155  struct reasm_frag_entry *frag,
156  bool last_frag);
157 
158 void reasm_free_entry(struct reasm_ip_entry *entry);
159 
160 #endif /* NMSG_BASE_IPREASM_H */