capt_get_packet(): check for key press only every 20ms
[iptraf-ng.git] / src / packet.c
blob2e4188f7590238aefaf72ff1211a36d8999be14c
1 /* For terms of usage/redistribution/modification see the LICENSE file */
2 /* For authors and contributors see the AUTHORS file */
4 /***
6 packet.c - routines to open the raw socket, read socket data and
7 adjust the initial packet pointer
9 ***/
11 #include "iptraf-ng-compat.h"
13 #include "deskman.h"
14 #include "error.h"
15 #include "options.h"
16 #include "fltdefs.h"
17 #include "fltselect.h"
18 #include "ipfilter.h"
19 #include "ifaces.h"
20 #include "packet.h"
21 #include "ipfrag.h"
23 #define pkt_cast_hdrp_l2off_t(hdr, pkt, off) \
24 do { \
25 pkt->hdr = (struct hdr *) (pkt->pkt_buf + off); \
26 } while (0)
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) \
33 do { \
34 pkt->hdr = (struct hdr *) (pkt->pkt_payload + off); \
35 } while (0)
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)
43 register int sum = 0;
44 u_short *addr = (u_short *)ip;
45 int len = ip->ihl * 4;
47 while (len > 1) {
48 sum += *addr++;
49 len -= 2;
52 while (sum >> 16)
53 sum = (sum & 0xffff) + (sum >> 16);
55 return ((u_short) ~sum) == 0;
58 static int packet_adjust(struct pkt_hdr *pkt)
60 int retval = 0;
62 switch (pkt->from->sll_hatype) {
63 case ARPHRD_ETHER:
64 case ARPHRD_LOOPBACK:
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;
69 break;
70 case ARPHRD_SLIP:
71 case ARPHRD_CSLIP:
72 case ARPHRD_SLIP6:
73 case ARPHRD_CSLIP6:
74 case ARPHRD_PPP:
75 case ARPHRD_TUNNEL:
76 case ARPHRD_SIT:
77 case ARPHRD_NONE:
78 case ARPHRD_IPGRE:
79 pkt->pkt_payload = pkt->pkt_buf;
80 break;
81 case ARPHRD_FRAD:
82 case ARPHRD_DLCI:
83 pkt->pkt_payload = pkt->pkt_buf;
84 pkt->pkt_payload += 4;
85 pkt->pkt_len -= 4;
86 break;
87 case ARPHRD_FDDI:
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);
92 break;
93 default:
94 /* return a NULL packet to signal an unrecognized link */
95 /* protocol to the caller. Hopefully, this switch statement */
96 /* will grow. */
97 pkt->pkt_payload = NULL;
98 retval = -1;
99 break;
101 return retval;
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) {
109 case ETH_P_IP:
110 pkt_cast_hdrp_l3(iphdr, pkt);
111 pkt->ip6_hdr = NULL;
112 break;
113 case ETH_P_IPV6:
114 pkt->iphdr = NULL;
115 pkt_cast_hdrp_l3(ip6_hdr, pkt);
116 break;
117 default:
118 pkt->iphdr = NULL;
119 pkt->ip6_hdr = NULL;
120 break;
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;
132 again:
133 packet_set_l3_hdrp(pkt);
134 switch (pkt->pkt_protocol) {
135 case ETH_P_IP: {
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)) {
150 int firstin = 0;
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)
161 *total_br =
162 processfragment(ip, &sport_tmp,
163 &dport_tmp,
164 &firstin);
166 if (!firstin)
167 return MORE_FRAGMENTS;
168 } else {
169 struct tcphdr *tcp;
170 struct udphdr *udp;
171 char *ip_payload = (char *) ip + pkt_iph_len(pkt);
173 switch (ip->protocol) {
174 case IPPROTO_TCP:
175 tcp = (struct tcphdr *) ip_payload;
176 sport_tmp = ntohs(tcp->source);
177 dport_tmp = ntohs(tcp->dest);
178 break;
179 case IPPROTO_UDP:
180 udp = (struct udphdr *) ip_payload;
181 sport_tmp = ntohs(udp->source);
182 dport_tmp = ntohs(udp->dest);
183 break;
184 default:
185 sport_tmp = 0;
186 dport_tmp = 0;
187 break;
190 if (total_br != NULL)
191 *total_br = pkt->pkt_len;
194 if (sport != NULL)
195 *sport = sport_tmp;
197 if (dport != NULL)
198 *dport = dport_tmp;
200 f_sport = sport_tmp;
201 f_dport = dport_tmp;
203 /* Process IP filter */
204 if ((ofilter.filtercode != 0)
206 (!ipfilter
207 (ip->saddr, ip->daddr, f_sport, f_dport, ip->protocol,
208 match_opposite)))
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);
214 goto again;
216 break; }
217 case ETH_P_IPV6: {
218 struct tcphdr *tcp;
219 struct udphdr *udp;
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)) {
225 case IPPROTO_TCP:
226 tcp = (struct tcphdr *) ip_payload;
227 if (sport)
228 *sport = ntohs(tcp->source);
229 if (dport)
230 *dport = ntohs(tcp->dest);
231 break;
232 case IPPROTO_UDP:
233 udp = (struct udphdr *) ip_payload;
234 if (sport)
235 *sport = ntohs(udp->source);
236 if (dport)
237 *dport = ntohs(udp->dest);
238 break;
239 default:
240 if (sport)
241 *sport = 0;
242 if (dport)
243 *dport = 0;
244 break;
246 break; }
247 case ETH_P_8021Q:
248 case ETH_P_QINQ1: /* ETH_P_QINQx are not officially */
249 case ETH_P_QINQ2: /* registered IDs */
250 case ETH_P_QINQ3:
251 case ETH_P_8021AD:
252 /* strip 802.1Q/QinQ/802.1ad VLAN header */
253 pkt->pkt_payload += 4;
254 pkt->pkt_len -= 4;
255 /* update network protocol */
256 pkt->pkt_protocol = ntohs(*((unsigned short *) pkt->pkt_payload));
257 goto again;
258 default:
259 /* not IPv4 and not IPv6: apply non-IP packet filter */
260 if (!nonipfilter(pkt->pkt_protocol)) {
261 return PACKET_FILTERED;
264 return PACKET_OK;
267 int packet_init(struct pkt_hdr *pkt)
269 pkt->pkt_payload = NULL;
270 pkt->ethhdr = NULL;
271 pkt->fddihdr = NULL;
272 pkt->iphdr = NULL;
273 pkt->ip6_hdr = NULL;
274 pkt->pkt_len = 0; /* signalize we have no packet prepared */
276 pkt->pkt_buf = NULL;
277 pkt->from = NULL;
279 return 0; /* all O.K. */
282 void packet_destroy(struct pkt_hdr *pkt __unused)
284 destroyfraglist();
287 int packet_is_first_fragment(struct pkt_hdr *pkt)
289 switch (pkt->pkt_protocol) {
290 case ETH_P_IP:
291 return ipv4_is_first_fragment(pkt->iphdr);
292 case ETH_P_IPV6:
293 /* FIXME: IPv6 can also be fragmented !!! */
294 /* fall through for now */
295 default:
296 return !0;