]>
Commit | Line | Data |
---|---|---|
2dd47c24 TB |
1 | /* |
2 | * Copyright (C) 2012 Tobias Brunner | |
3 | * Hochschule fuer Technik Rapperswil | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | * for more details. | |
14 | */ | |
15 | ||
16 | ||
17 | #include "ip_packet.h" | |
18 | ||
19 | #include <library.h> | |
f05b4272 | 20 | #include <utils/debug.h> |
2dd47c24 | 21 | |
ae8ac58c | 22 | #include <sys/types.h> |
2dd47c24 TB |
23 | #include <netinet/in.h> |
24 | #include <netinet/ip.h> | |
b6a07151 | 25 | #ifdef HAVE_NETINET_IP6_H |
2dd47c24 | 26 | #include <netinet/ip6.h> |
b6a07151 | 27 | #endif |
2dd47c24 TB |
28 | |
29 | typedef struct private_ip_packet_t private_ip_packet_t; | |
30 | ||
31 | /** | |
32 | * Private additions to ip_packet_t. | |
33 | */ | |
34 | struct private_ip_packet_t { | |
35 | ||
36 | /** | |
37 | * Public members | |
38 | */ | |
39 | ip_packet_t public; | |
40 | ||
41 | /** | |
42 | * Source address | |
43 | */ | |
44 | host_t *src; | |
45 | ||
46 | /** | |
47 | * Destination address | |
48 | */ | |
49 | host_t *dst; | |
50 | ||
51 | /** | |
52 | * IP packet | |
53 | */ | |
54 | chunk_t packet; | |
55 | ||
56 | /** | |
57 | * IP version | |
58 | */ | |
59 | u_int8_t version; | |
60 | ||
61 | /** | |
62 | * Protocol|Next Header field | |
63 | */ | |
64 | u_int8_t next_header; | |
65 | ||
66 | }; | |
67 | ||
68 | METHOD(ip_packet_t, get_version, u_int8_t, | |
69 | private_ip_packet_t *this) | |
70 | { | |
71 | return this->version; | |
72 | } | |
73 | ||
74 | METHOD(ip_packet_t, get_source, host_t*, | |
75 | private_ip_packet_t *this) | |
76 | { | |
77 | return this->src; | |
78 | } | |
79 | ||
80 | METHOD(ip_packet_t, get_destination, host_t*, | |
81 | private_ip_packet_t *this) | |
82 | { | |
83 | return this->dst; | |
84 | } | |
85 | ||
86 | METHOD(ip_packet_t, get_encoding, chunk_t, | |
87 | private_ip_packet_t *this) | |
88 | { | |
89 | return this->packet; | |
90 | } | |
91 | ||
92 | METHOD(ip_packet_t, get_next_header, u_int8_t, | |
93 | private_ip_packet_t *this) | |
94 | { | |
95 | return this->next_header; | |
96 | } | |
97 | ||
5f35b733 | 98 | METHOD(ip_packet_t, clone_, ip_packet_t*, |
2dd47c24 TB |
99 | private_ip_packet_t *this) |
100 | { | |
2b84ccd6 | 101 | return ip_packet_create(chunk_clone(this->packet)); |
2dd47c24 TB |
102 | } |
103 | ||
104 | METHOD(ip_packet_t, destroy, void, | |
105 | private_ip_packet_t *this) | |
106 | { | |
107 | this->src->destroy(this->src); | |
108 | this->dst->destroy(this->dst); | |
109 | chunk_free(&this->packet); | |
110 | free(this); | |
111 | } | |
112 | ||
113 | /** | |
114 | * Described in header. | |
115 | */ | |
116 | ip_packet_t *ip_packet_create(chunk_t packet) | |
117 | { | |
118 | private_ip_packet_t *this; | |
119 | u_int8_t version, next_header; | |
120 | host_t *src, *dst; | |
121 | ||
122 | if (packet.len < 1) | |
123 | { | |
124 | DBG1(DBG_ESP, "IP packet too short"); | |
125 | goto failed; | |
126 | } | |
127 | ||
128 | version = (packet.ptr[0] & 0xf0) >> 4; | |
129 | ||
130 | switch (version) | |
131 | { | |
132 | case 4: | |
133 | { | |
39e9af96 | 134 | struct ip *ip; |
2dd47c24 | 135 | |
39e9af96 | 136 | if (packet.len < sizeof(struct ip)) |
2dd47c24 TB |
137 | { |
138 | DBG1(DBG_ESP, "IPv4 packet too short"); | |
139 | goto failed; | |
140 | } | |
39e9af96 | 141 | ip = (struct ip*)packet.ptr; |
293515f9 MW |
142 | /* remove any RFC 4303 TFC extra padding */ |
143 | packet.len = min(packet.len, untoh16(&ip->ip_len)); | |
144 | ||
2dd47c24 | 145 | src = host_create_from_chunk(AF_INET, |
39e9af96 | 146 | chunk_from_thing(ip->ip_src), 0); |
2dd47c24 | 147 | dst = host_create_from_chunk(AF_INET, |
39e9af96 TB |
148 | chunk_from_thing(ip->ip_dst), 0); |
149 | next_header = ip->ip_p; | |
2dd47c24 TB |
150 | break; |
151 | } | |
b6a07151 | 152 | #ifdef HAVE_NETINET_IP6_H |
2dd47c24 TB |
153 | case 6: |
154 | { | |
155 | struct ip6_hdr *ip; | |
156 | ||
157 | if (packet.len < sizeof(struct ip6_hdr)) | |
158 | { | |
159 | DBG1(DBG_ESP, "IPv6 packet too short"); | |
160 | goto failed; | |
161 | } | |
162 | ip = (struct ip6_hdr*)packet.ptr; | |
293515f9 MW |
163 | /* remove any RFC 4303 TFC extra padding */ |
164 | packet.len = min(packet.len, untoh16(&ip->ip6_plen)); | |
165 | ||
2dd47c24 TB |
166 | src = host_create_from_chunk(AF_INET6, |
167 | chunk_from_thing(ip->ip6_src), 0); | |
168 | dst = host_create_from_chunk(AF_INET6, | |
169 | chunk_from_thing(ip->ip6_dst), 0); | |
170 | next_header = ip->ip6_nxt; | |
43e0cb65 | 171 | break; |
2dd47c24 | 172 | } |
b6a07151 | 173 | #endif /* HAVE_NETINET_IP6_H */ |
2dd47c24 TB |
174 | default: |
175 | DBG1(DBG_ESP, "unsupported IP version"); | |
176 | goto failed; | |
177 | } | |
178 | ||
179 | INIT(this, | |
180 | .public = { | |
181 | .get_version = _get_version, | |
182 | .get_source = _get_source, | |
183 | .get_destination = _get_destination, | |
184 | .get_next_header = _get_next_header, | |
185 | .get_encoding = _get_encoding, | |
5f35b733 | 186 | .clone = _clone_, |
2dd47c24 TB |
187 | .destroy = _destroy, |
188 | }, | |
189 | .src = src, | |
190 | .dst = dst, | |
191 | .packet = packet, | |
192 | .version = version, | |
193 | .next_header = next_header, | |
194 | ); | |
195 | return &this->public; | |
196 | ||
197 | failed: | |
198 | chunk_free(&packet); | |
199 | return NULL; | |
200 | } |