1 /* For terms of usage/redistribution/modification see the LICENSE file */
2 /* For authors and contributors see the AUTHORS file */
6 packet.c - routines to open the raw socket, read socket data and
7 adjust the initial packet pointer
11 #include "iptraf-ng-compat.h"
17 #include "fltselect.h"
23 #define pkt_cast_hdrp_l2off_t(hdr, pkt, off) \
25 pkt->hdr = (struct hdr *) (pkt->pkt_buf + off); \
28 #define pkt_cast_hdrp_l2(hdr, pkt) \
29 pkt_cast_hdrp_l2off_t(hdr, pkt, 0)
32 #define pkt_cast_hdrp_l3off_t(hdr, pkt, off) \
34 pkt->hdr = (struct hdr *) (pkt->pkt_payload + off); \
37 #define pkt_cast_hdrp_l3(hdr, pkt) \
38 pkt_cast_hdrp_l3off_t(hdr, pkt, 0)
40 /* code taken from http://www.faqs.org/rfcs/rfc1071.html. See section 4.1 "C" */
41 static int verify_ipv4_hdr_chksum(struct iphdr
*ip
)
44 u_short
*addr
= (u_short
*)ip
;
45 int len
= ip
->ihl
* 4;
53 sum
= (sum
& 0xffff) + (sum
>> 16);
55 return ((u_short
) ~sum
) == 0;
58 static int packet_adjust(struct pkt_hdr
*pkt
)
62 switch (pkt
->from
->sll_hatype
) {
65 pkt_cast_hdrp_l2(ethhdr
, pkt
);
66 pkt
->pkt_payload
= pkt
->pkt_buf
;
67 pkt
->pkt_payload
+= ETH_HLEN
;
68 pkt
->pkt_len
-= ETH_HLEN
;
79 pkt
->pkt_payload
= pkt
->pkt_buf
;
83 pkt
->pkt_payload
= pkt
->pkt_buf
;
84 pkt
->pkt_payload
+= 4;
88 pkt_cast_hdrp_l2(fddihdr
, pkt
);
89 pkt
->pkt_payload
= pkt
->pkt_buf
;
90 pkt
->pkt_payload
+= sizeof(struct fddihdr
);
91 pkt
->pkt_len
-= sizeof(struct fddihdr
);
94 /* return a NULL packet to signal an unrecognized link */
95 /* protocol to the caller. Hopefully, this switch statement */
97 pkt
->pkt_payload
= NULL
;
104 /* initialize all layer3 protocol pointers (we need to initialize all
105 * of them, because of case we change pkt->pkt_protocol) */
106 static void packet_set_l3_hdrp(struct pkt_hdr
*pkt
)
108 switch (pkt
->pkt_protocol
) {
110 pkt_cast_hdrp_l3(iphdr
, pkt
);
115 pkt_cast_hdrp_l3(ip6_hdr
, pkt
);
124 int packet_process(struct pkt_hdr
*pkt
, unsigned int *total_br
,
125 in_port_t
*sport
, in_port_t
*dport
,
126 int match_opposite
, int v6inv4asv6
)
128 /* move packet pointer (pkt->pkt_payload) past data link header */
129 if (packet_adjust(pkt
) != 0)
130 return INVALID_PACKET
;
133 packet_set_l3_hdrp(pkt
);
134 switch (pkt
->pkt_protocol
) {
136 struct iphdr
*ip
= pkt
->iphdr
;
137 in_port_t f_sport
= 0, f_dport
= 0;
139 if (!verify_ipv4_hdr_chksum(ip
))
140 return CHECKSUM_ERROR
;
142 if ((ip
->protocol
== IPPROTO_TCP
|| ip
->protocol
== IPPROTO_UDP
)
143 && (sport
!= NULL
&& dport
!= NULL
)) {
144 in_port_t sport_tmp
, dport_tmp
;
147 * Process TCP/UDP fragments
149 if (ipv4_is_fragmented(ip
)) {
153 * total_br contains total byte count of all fragments
154 * not yet retrieved. Will differ only if fragments
155 * arrived before the first fragment, in which case
156 * the total accumulated fragment sizes will be returned
157 * once the first fragment arrives.
160 if (total_br
!= NULL
)
162 processfragment(ip
, &sport_tmp
,
167 return MORE_FRAGMENTS
;
171 char *ip_payload
= (char *) ip
+ pkt_iph_len(pkt
);
173 switch (ip
->protocol
) {
175 tcp
= (struct tcphdr
*) ip_payload
;
176 sport_tmp
= ntohs(tcp
->source
);
177 dport_tmp
= ntohs(tcp
->dest
);
180 udp
= (struct udphdr
*) ip_payload
;
181 sport_tmp
= ntohs(udp
->source
);
182 dport_tmp
= ntohs(udp
->dest
);
190 if (total_br
!= NULL
)
191 *total_br
= pkt
->pkt_len
;
203 /* Process IP filter */
204 if ((ofilter
.filtercode
!= 0)
207 (ip
->saddr
, ip
->daddr
, f_sport
, f_dport
, ip
->protocol
,
209 return PACKET_FILTERED
;
210 if (v6inv4asv6
&& (ip
->protocol
== IPPROTO_IPV6
)) {
211 pkt
->pkt_protocol
= ETH_P_IPV6
;
212 pkt
->pkt_payload
+= pkt_iph_len(pkt
);
213 pkt
->pkt_len
-= pkt_iph_len(pkt
);
220 struct ip6_hdr
*ip6
= pkt
->ip6_hdr
;
221 char *ip_payload
= (char *) ip6
+ pkt_iph_len(pkt
);
223 //TODO: Filter packets
224 switch (pkt_ip_protocol(pkt
)) {
226 tcp
= (struct tcphdr
*) ip_payload
;
228 *sport
= ntohs(tcp
->source
);
230 *dport
= ntohs(tcp
->dest
);
233 udp
= (struct udphdr
*) ip_payload
;
235 *sport
= ntohs(udp
->source
);
237 *dport
= ntohs(udp
->dest
);
248 case ETH_P_QINQ1
: /* ETH_P_QINQx are not officially */
249 case ETH_P_QINQ2
: /* registered IDs */
252 /* strip 802.1Q/QinQ/802.1ad VLAN header */
253 pkt
->pkt_payload
+= 4;
255 /* update network protocol */
256 pkt
->pkt_protocol
= ntohs(*((unsigned short *) pkt
->pkt_payload
));
259 /* not IPv4 and not IPv6: apply non-IP packet filter */
260 if (!nonipfilter(pkt
->pkt_protocol
)) {
261 return PACKET_FILTERED
;
267 int packet_init(struct pkt_hdr
*pkt
)
269 pkt
->pkt_payload
= NULL
;
274 pkt
->pkt_len
= 0; /* signalize we have no packet prepared */
279 return 0; /* all O.K. */
282 void packet_destroy(struct pkt_hdr
*pkt __unused
)
287 int packet_is_first_fragment(struct pkt_hdr
*pkt
)
289 switch (pkt
->pkt_protocol
) {
291 return ipv4_is_first_fragment(pkt
->iphdr
);
293 /* FIXME: IPv6 can also be fragmented !!! */
294 /* fall through for now */