1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! User Datagram Protocol related packet processing
use prelude::*;

/// The UDP parser
pub struct UdpParser;

impl Parsable<PathIp> for UdpParser {
    /// Parse an `UdpPacket` from an `&[u8]`
    fn parse<'a>(&mut self,
                 input: &'a [u8],
                 result: Option<&ParserResultVec>,
                 path: Option<&mut PathIp>)
                 -> IResult<&'a [u8], ParserResult> {
        do_parse!(input,
            // Check the IP protocol from the parent parser (IPv4 or IPv6)
            expr_opt!(match result {
                Some(vector) => match vector.last() {
                    // Check the parent node for the correct IP protocol
                    Some(ref any) => match (any.downcast_ref::<Ipv4Packet>(),
                                            any.downcast_ref::<Ipv6Packet>()) {

                        // IPv4
                        (Some(ipv4), _) => if ipv4.protocol == IpProtocol::Udp {
                            Some(())
                        } else {
                            None
                        },

                        // IPv6
                        (_, Some(ipv6)) => if ipv6.next_header == IpProtocol::Udp {
                            Some(())
                        } else {
                            None
                        },

                        _ => None,
                    },

                    // Previous result found, but not correct parent
                    _ => None,
                },
                // Parse also if no result is given, for testability
                None => Some(()),
            }) >>

            // Parse the header
            src: be_u16 >>
            dst: be_u16 >>
            len: be_u16 >>
            checksum: be_u16 >>

            // Try to track the connection
            path_error: expr_opt!(match track_connection(path, result, src, dst) {
                Err(e) => Some(Some(e.code)),
                Ok(()) => Some(None),
            }) >>

            (Box::new(UdpPacket {
                header: UdpHeader {
                    source_port: src,
                    dest_port: dst,
                    length: len,
                    checksum: checksum,
                },
                path_error: path_error,
            }))
        )
    }
}

impl fmt::Display for UdpParser {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "UDP")
    }
}

#[derive(Debug, Eq, PartialEq)]
/// Representation of an User Datagram Protocol packet
pub struct UdpPacket {
    /// The header of the UDP packet
    pub header: UdpHeader,

    /// Set to some error code if the connection tracking failed
    pub path_error: Option<PathErrorType>,
}

#[derive(Debug, Eq, PartialEq)]
/// Representation of an User Datagram Protocol packet header
pub struct UdpHeader {
    /// This field identifies the sender's port when meaningful and should be assumed to be the
    /// port to reply to if needed. If not used, then it should be zero. If the source host is the
    /// client, the port number is likely to be an ephemeral port number. If the source host is the
    /// server, the port number is likely to be a well-known port number.
    pub source_port: u16,

    /// This field identifies the receiver's port and is required. Similar to source port number,
    /// if the client is the destination host then the port number will likely be an ephemeral port
    /// number and if the destination host is the server then the port number will likely be a
    /// well-known port number.
    pub dest_port: u16,

    /// A field that specifies the length in bytes of the UDP header and UDP data. The minimum
    /// length is 8 bytes because that is the length of the header. The field size sets a
    /// theoretical limit of 65,535 bytes (8 byte header + 65,527 bytes of data) for a UDP
    /// datagram. The practical limit for the data length which is imposed by the underlying IPv4
    /// protocol is 65,507 bytes (65,535 − 8 byte UDP header − 20 byte IP header).
    /// In IPv6 jumbograms it is possible to have UDP packets of size greater than 65,535 bytes.
    /// RFC 2675 specifies that the length field is set to zero if the length of the UDP header
    /// plus UDP data is greater than 65,535.
    pub length: u16,

    /// The checksum field may be used for error-checking of the header and data. This field is
    /// optional in IPv4, and mandatory in IPv6. The field carries all-zeros if unused.
    pub checksum: u16,
}