pnet_transport/
lib.rs

1// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Support for implementing transport layer protocols
10//!
11//! The transport module provides the ability to send and receive packets at
12//! the transport layer using IPv4 or IPv6. It also enables layer 3 networking
13//! for specific transport protocols, using IPv4 only.
14//!
15//! Note that this is limited by operating system support - for example, on OS
16//! X and FreeBSD, it is impossible to implement protocols which are already
17//! implemented in the kernel such as TCP and UDP.
18
19#![deny(warnings)]
20#![macro_use]
21
22extern crate libc;
23extern crate pnet_packet;
24extern crate pnet_sys;
25
26use self::TransportChannelType::{Layer3, Layer4};
27use self::TransportProtocol::{Ipv4, Ipv6};
28use pnet_packet::icmp::IcmpPacket;
29use pnet_packet::icmpv6::Icmpv6Packet;
30use pnet_packet::ip::IpNextHeaderProtocol;
31use pnet_packet::ipv4::Ipv4Packet;
32use pnet_packet::tcp::TcpPacket;
33use pnet_packet::udp::UdpPacket;
34use pnet_packet::Packet;
35
36use std::io;
37use std::io::Error;
38#[cfg(unix)]
39use std::io::ErrorKind;
40use std::mem;
41use std::net::{self, IpAddr};
42use std::sync::Arc;
43#[cfg(unix)]
44use std::time::Duration;
45
46/// Represents a transport layer protocol.
47#[derive(Clone, Copy)]
48pub enum TransportProtocol {
49    /// Represents a transport protocol built on top of IPv4
50    Ipv4(IpNextHeaderProtocol),
51    /// Represents a transport protocol built on top of IPv6
52    Ipv6(IpNextHeaderProtocol),
53}
54
55#[repr(u8)]
56#[derive(Clone,Copy,Debug,PartialEq)]
57pub enum Ecn {
58    NotEct = 0x0,
59    Ect1 = 0x1,
60    Ect0 = 0x2,
61    CE = 0x3
62}
63
64impl From<u8> for Ecn {
65    fn from(value: u8) -> Ecn {
66        let ecn_bits = value & 0x3;
67        if ecn_bits == Ecn::Ect0 as u8 {
68            return Ecn::Ect0
69        } else if ecn_bits == Ecn::Ect1 as u8 {
70            return Ecn::Ect1
71        } else if ecn_bits == Ecn::CE as u8 {
72            return Ecn::CE
73        }
74        Ecn::NotEct
75    }
76}
77
78/// Type of transport channel to present.
79#[derive(Clone, Copy)]
80pub enum TransportChannelType {
81    /// The application will send and receive transport layer packets.
82    Layer4(TransportProtocol),
83    /// The application will send and receive IPv4 packets, with the specified transport protocol.
84    Layer3(IpNextHeaderProtocol),
85}
86
87/// Structure used for sending at the transport layer. Should be created with `transport_channel()`.
88pub struct TransportSender {
89    pub socket: Arc<pnet_sys::FileDesc>,
90    channel_type: TransportChannelType,
91}
92
93/// Structure used for receiving at the transport layer. Should be created with `transport_channel()`.
94pub struct TransportReceiver {
95    pub socket: Arc<pnet_sys::FileDesc>,
96    pub buffer: Vec<u8>,
97    pub channel_type: TransportChannelType,
98}
99
100/// Structure used for holding all configurable options for describing possible options
101/// for transport channels.
102#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
103pub struct Config {
104    time_to_live: u8,
105}
106
107/// Create a new `(TransportSender, TransportReceiver)` pair.
108///
109/// This allows for sending and receiving packets at the transport layer. The buffer size should be
110/// large enough to handle the largest packet you wish to receive.
111///
112/// The channel type specifies what layer to send and receive packets at, and the transport
113/// protocol you wish to implement. For example, `Layer4(Ipv4(IpNextHeaderProtocols::Udp))` would
114/// allow sending and receiving UDP packets using IPv4; whereas `Layer3(IpNextHeaderProtocols::Udp)`
115/// would include the IPv4 Header in received values, and require manual construction of an IP
116/// header when sending.
117pub fn transport_channel(
118    buffer_size: usize,
119    channel_type: TransportChannelType,
120) -> io::Result<(TransportSender, TransportReceiver)> {
121    // This hack makes sure that winsock is initialised
122    let _ = {
123        let ip = net::Ipv4Addr::new(255, 255, 255, 255);
124        let sockaddr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 0));
125
126        net::UdpSocket::bind(sockaddr)
127    };
128
129    let socket = unsafe {
130        match channel_type {
131            Layer4(Ipv4(IpNextHeaderProtocol(proto))) | Layer3(IpNextHeaderProtocol(proto)) => {
132                pnet_sys::socket(pnet_sys::AF_INET, pnet_sys::SOCK_RAW, proto as libc::c_int)
133            }
134            Layer4(Ipv6(IpNextHeaderProtocol(proto))) => {
135                pnet_sys::socket(pnet_sys::AF_INET6, pnet_sys::SOCK_RAW, proto as libc::c_int)
136            }
137        }
138    };
139    if socket == pnet_sys::INVALID_SOCKET {
140        return Err(Error::last_os_error());
141    }
142
143    if matches!(channel_type, Layer3(_) | Layer4(Ipv4(_))) {
144        let hincl: libc::c_int = match channel_type {
145            Layer4(..) => 0,
146            _ => 1,
147        };
148        let res = unsafe {
149            pnet_sys::setsockopt(
150                socket,
151                pnet_sys::IPPROTO_IP,
152                pnet_sys::IP_HDRINCL,
153                (&hincl as *const libc::c_int) as pnet_sys::Buf,
154                mem::size_of::<libc::c_int>() as pnet_sys::SockLen,
155            )
156        };
157        if res == -1 {
158            let err = Error::last_os_error();
159            unsafe {
160                pnet_sys::close(socket);
161            }
162            return Err(err);
163        }
164    }
165
166    let sock = Arc::new(pnet_sys::FileDesc { fd: socket });
167    let sender = TransportSender {
168        socket: sock.clone(),
169        channel_type,
170    };
171    let receiver = TransportReceiver {
172        socket: sock,
173        buffer: vec![0; buffer_size],
174        channel_type,
175    };
176
177    Ok((sender, receiver))
178}
179
180/// Create a new `(TransportSender, TransportReceiver)` pair using the additional
181/// options specified.
182///
183/// For a more exhaustive descriptive, see above.
184pub fn transport_channel_with(
185    buffer_size: usize,
186    channel_type: TransportChannelType,
187    configuration: Config,
188) -> io::Result<(TransportSender, TransportReceiver)> {
189    let (mut sender, receiver) = transport_channel(buffer_size, channel_type)?;
190
191    sender.set_ttl(configuration.time_to_live)?;
192    Ok((sender, receiver))
193}
194
195/// Sets a socket option whose value is a byte. Close the socket on error.
196fn set_sockopt_u8(
197    socket: Arc<pnet_sys::FileDesc>,
198    level: libc::c_int,
199    name: libc::c_int,
200    value: u8,
201) -> io::Result<()> {
202    let value = value as i32;
203    let res = unsafe {
204        pnet_sys::setsockopt(
205            socket.fd,
206            level,
207            name,
208            (&value as *const libc::c_int) as pnet_sys::Buf,
209            mem::size_of::<libc::c_int>() as pnet_sys::SockLen,
210        )
211    };
212
213    match res {
214        -1 => {
215            let err = Error::last_os_error();
216            unsafe {
217                pnet_sys::close(socket.fd);
218            }
219            Err(err)
220        }
221        _ => Ok(()),
222    }
223}
224
225impl TransportSender {
226    fn send<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
227        let mut caddr = unsafe { mem::zeroed() };
228        let sockaddr = match dst {
229            IpAddr::V4(ip_addr) => net::SocketAddr::V4(net::SocketAddrV4::new(ip_addr, 0)),
230            IpAddr::V6(ip_addr) => net::SocketAddr::V6(net::SocketAddrV6::new(ip_addr, 0, 0, 0)),
231        };
232        let slen = pnet_sys::addr_to_sockaddr(sockaddr, &mut caddr);
233        let caddr_ptr = (&caddr as *const pnet_sys::SockAddrStorage) as *const pnet_sys::SockAddr;
234
235        pnet_sys::send_to(self.socket.fd, packet.packet(), caddr_ptr, slen)
236    }
237
238    /// Send a packet to the provided destination.
239    #[inline]
240    pub fn send_to<T: Packet>(&mut self, packet: T, destination: IpAddr) -> io::Result<usize> {
241        self.send_to_impl(packet, destination)
242    }
243
244    /// Sets a time-to-live on the socket, which then applies for all packets sent.
245    pub fn set_ttl(&mut self, time_to_live: u8) -> io::Result<()> {
246        let (level, name) = match self.channel_type {
247            Layer4(Ipv4(_)) | Layer3(_) => (pnet_sys::IPPROTO_IP, pnet_sys::IP_TTL),
248            Layer4(Ipv6(_)) => (pnet_sys::IPPROTO_IPV6, pnet_sys::IPV6_UNICAST_HOPS),
249        };
250        set_sockopt_u8(self.socket.clone(), level, name, time_to_live)
251    }
252
253    /// Sets an ECN marking on the socket, which then applies for all packets sent.
254    #[cfg(unix)]
255    pub fn set_ecn(&mut self, tos: Ecn) -> io::Result<()> {
256        let (level, name) = match self.channel_type {
257            Layer4(Ipv4(_)) | Layer3(_) => (pnet_sys::IPPROTO_IP, pnet_sys::IP_TOS),
258            Layer4(Ipv6(_)) => (pnet_sys::IPPROTO_IPV6, pnet_sys::IPV6_TCLASS),
259        };
260        set_sockopt_u8(self.socket.clone(), level, name, tos as u8)
261    }
262
263    #[cfg(all(
264        not(target_os = "freebsd"),
265        not(any(target_os = "macos", target_os = "ios", target_os = "tvos"))
266    ))]
267    fn send_to_impl<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
268        self.send(packet, dst)
269    }
270
271    #[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "ios", target_os = "tvos"))]
272    fn send_to_impl<T: Packet>(&mut self, packet: T, dst: IpAddr) -> io::Result<usize> {
273        use pnet_packet::ipv4::MutableIpv4Packet;
274        use pnet_packet::MutablePacket;
275
276        // FreeBSD and OS X expect total length and fragment offset fields of IPv4
277        // packets to be in host byte order rather than network byte order. Fragment offset is the
278        // ip_off field in the ip struct and contains both the offset and the three flag bits.
279        // See `man 4 ip`/Raw IP Sockets)
280        if let Layer3(_) = self.channel_type {
281            let mut mut_slice: Vec<u8> = vec![0; packet.packet().len()];
282
283            let mut new_packet = MutableIpv4Packet::new(&mut mut_slice[..]).unwrap();
284            new_packet.clone_from(&packet);
285            let length = new_packet.get_total_length().to_be();
286            new_packet.set_total_length(length);
287            {
288                // Turn fragment offset into host order
289                let d = new_packet.packet_mut();
290                let host_order = u16::from_be((d[6] as u16) << 8 | d[7] as u16);
291                d[6] = (host_order >> 8) as u8;
292                d[7] = host_order as u8;
293            }
294            return self.send(new_packet, dst);
295        }
296
297        self.send(packet, dst)
298    }
299}
300
301/// Create an iterator for some packet type.
302///
303/// Usage:
304/// ```ignore
305/// transport_channel_iterator!(Ipv4Packet, // Type to iterate over
306///                             Ipv4TransportChannelIterator, // Name for iterator struct
307///                             ipv4_packet_iter) // Name of function to create iterator
308/// ```
309#[macro_export]
310macro_rules! transport_channel_iterator {
311    ($ty:ident, $iter:ident, $func:ident) => {
312        transport_channel_iterator!($ty, $iter, $func, stringify!($ty));
313    };
314    ($ty:ident, $iter:ident, $func:ident, $tyname:expr) => {
315        #[doc = "An iterator over packets of type `"]
316        #[doc = $tyname]
317        #[doc = "`."]
318        pub struct $iter<'a> {
319            tr: &'a mut TransportReceiver,
320        }
321
322        #[doc = "Return a packet iterator with packets of type `"]
323        #[doc = $tyname]
324        #[doc = "` for some transport receiver."]
325        pub fn $func(tr: &mut TransportReceiver) -> $iter {
326            $iter { tr: tr }
327        }
328
329        impl<'a> $iter<'a> {
330            #[doc = "Get the next (`"]
331            #[doc = $tyname ]
332            #[doc = "`, `IpAddr`) pair for the given channel."]
333            pub fn next(&mut self) -> io::Result<($ty, IpAddr)> {
334                let mut caddr: pnet_sys::SockAddrStorage = unsafe { mem::zeroed() };
335                let res =
336                    pnet_sys::recv_from(self.tr.socket.fd, &mut self.tr.buffer[..], &mut caddr);
337
338                let offset = match self.tr.channel_type {
339                    Layer4(Ipv4(_)) => {
340                        let ip_header = Ipv4Packet::new(&self.tr.buffer[..]).unwrap();
341
342                        ip_header.get_header_length() as usize * 4usize
343                    }
344                    Layer3(_) => {
345                        fixup_packet(&mut self.tr.buffer[..]);
346
347                        0
348                    }
349                    _ => 0,
350                };
351                return match res {
352                    Ok(len) => {
353                        let packet = $ty::new(&self.tr.buffer[offset..len]).unwrap();
354                        let addr = pnet_sys::sockaddr_to_addr(
355                            &caddr,
356                            mem::size_of::<pnet_sys::SockAddrStorage>(),
357                        );
358                        let ip = match addr.unwrap() {
359                            net::SocketAddr::V4(sa) => IpAddr::V4(*sa.ip()),
360                            net::SocketAddr::V6(sa) => IpAddr::V6(*sa.ip()),
361                        };
362                        Ok((packet, ip))
363                    }
364                    Err(e) => Err(e),
365                };
366
367                #[cfg(any(
368                    target_os = "freebsd",
369                    target_os = "macos",
370                    target_os = "ios",
371                    target_os = "tvos"
372                ))]
373                fn fixup_packet(buffer: &mut [u8]) {
374                    use pnet_packet::ipv4::MutableIpv4Packet;
375
376                    let buflen = buffer.len();
377                    let mut new_packet = MutableIpv4Packet::new(buffer).unwrap();
378
379                    let length = u16::from_be(new_packet.get_total_length());
380                    new_packet.set_total_length(length);
381
382                    // OS X does this awesome thing where it removes the header length
383                    // from the total length sometimes.
384                    let length = new_packet.get_total_length() as usize
385                        + (new_packet.get_header_length() as usize * 4usize);
386                    if length == buflen {
387                        new_packet.set_total_length(length as u16)
388                    }
389
390                    let offset = u16::from_be(new_packet.get_fragment_offset());
391                    new_packet.set_fragment_offset(offset);
392                }
393
394                #[cfg(all(
395                    not(target_os = "freebsd"),
396                    not(any(target_os = "macos", target_os = "ios", target_os = "tvos"))
397                ))]
398                fn fixup_packet(_buffer: &mut [u8]) {}
399            }
400
401            /// Wait only for a timespan of `t` to receive some data, then return. If no data was
402            /// received, then `Ok(None)` is returned.
403            #[cfg(unix)]
404            pub fn next_with_timeout(&mut self, t: Duration) -> io::Result<Option<($ty, IpAddr)>> {
405                let socket_fd = self.tr.socket.fd;
406
407                let old_timeout = match pnet_sys::get_socket_receive_timeout(socket_fd) {
408                    Err(e) => {
409                        eprintln!("Can not get socket timeout before receiving: {}", e);
410                        return Err(e);
411                    }
412                    Ok(t) => t,
413                };
414
415                match pnet_sys::set_socket_receive_timeout(socket_fd, t) {
416                    Err(e) => {
417                        eprintln!("Can not set socket timeout for receiving: {}", e);
418                        return Err(e);
419                    }
420                    Ok(_) => {}
421                }
422
423                let r = match self.next() {
424                    Ok(r) => Ok(Some(r)),
425                    Err(e) => match e.kind() {
426                        ErrorKind::WouldBlock => Ok(None),
427                        _ => Err(e),
428                    },
429                };
430
431                match pnet_sys::set_socket_receive_timeout(socket_fd, old_timeout) {
432                    Err(e) => {
433                        eprintln!("Can not reset socket timeout after receiving: {}", e);
434                    }
435                    _ => {}
436                };
437
438                r
439            }
440        }
441    };
442}
443
444transport_channel_iterator!(Ipv4Packet, Ipv4TransportChannelIterator, ipv4_packet_iter);
445
446transport_channel_iterator!(UdpPacket, UdpTransportChannelIterator, udp_packet_iter);
447
448transport_channel_iterator!(IcmpPacket, IcmpTransportChannelIterator, icmp_packet_iter);
449
450transport_channel_iterator!(
451    Icmpv6Packet,
452    Icmpv6TransportChannelIterator,
453    icmpv6_packet_iter
454);
455
456transport_channel_iterator!(TcpPacket, TcpTransportChannelIterator, tcp_packet_iter);