1
//! Implementation for encoding and decoding of ChanCells.
2

            
3
use super::{CELL_DATA_LEN, ChanCell};
4
use crate::Error;
5
use crate::chancell::{ChanCmd, ChanMsg, CircId};
6
use tor_bytes::{self, Reader, Writer};
7
use tor_error::internal;
8

            
9
use bytes::BytesMut;
10

            
11
/// This object can be used to encode and decode channel cells.
12
///
13
/// NOTE: only link protocol versions 3 and higher are supported.
14
/// VERSIONS cells are not supported via the encoder/decoder, since
15
/// VERSIONS cells always use a two-byte circuit-ID for backwards
16
/// compatibility with protocol versions < 4.
17
///
18
/// The implemented format is one of the following:
19
///
20
/// Variable-length cells (since protocol versions 2 and 3 respectively):
21
/// ```ignore
22
///     u32 circid;
23
///     u8 command;
24
///     u16 len;
25
///     u8 body[len];
26
/// ```
27
///
28
/// Fixed-width cells (since protocol version 1 and 4 respectively):
29
/// ```ignore
30
///     u32 circid;
31
///     u8 command;
32
///     u8 body[509];
33
/// ```
34
pub struct ChannelCodec {
35
    #[allow(dead_code)] // We don't support any link versions where this matters
36
    /// The link protocol version being used for this channel.
37
    ///
38
    /// (We don't currently support any versions of the link protocol
39
    /// where this version matters, but for protocol versions below 4, it would
40
    /// affect the length of the circuit ID.)
41
    link_version: u16,
42
}
43

            
44
impl ChannelCodec {
45
    /// Create a new ChannelCodec with a given link protocol version
46
4524
    pub fn new(link_version: u16) -> Self {
47
4524
        ChannelCodec { link_version }
48
4524
    }
49

            
50
    /// Return the link protocol version of this codec.
51
728
    pub fn link_version(&self) -> u16 {
52
728
        self.link_version
53
728
    }
54

            
55
    /// Write the given cell into the provided BytesMut object.
56
86
    pub fn write_cell<M: ChanMsg>(
57
86
        &mut self,
58
86
        item: ChanCell<M>,
59
86
        dst: &mut BytesMut,
60
86
    ) -> crate::Result<()> {
61
86
        let ChanCell { circid, msg } = item;
62
86
        let cmd = msg.cmd();
63
86
        dst.write_u32(CircId::get_or_zero(circid));
64
86
        dst.write_u8(cmd.into());
65

            
66
        // this is typically 5, but not always
67
        // (for example if we were given a non-empty `dst`)
68
86
        let pos = dst.len();
69

            
70
        // now write the cell body and handle the length.
71
86
        if cmd.is_var_cell() {
72
16
            dst.write_u16(0);
73
16
            msg.encode_onto(dst)?;
74
16
            let len = dst.len() - pos - 2;
75
16
            if len > u16::MAX as usize {
76
                return Err(Error::Internal(internal!("ran out of space for varcell")));
77
16
            }
78
            // go back and set the length.
79
16
            *(<&mut [u8; 2]>::try_from(&mut dst[pos..pos + 2])
80
16
                .expect("two-byte slice was not two bytes!?")) = (len as u16).to_be_bytes();
81
        } else {
82
70
            msg.encode_onto(dst)?;
83
70
            let len = dst.len() - pos;
84
70
            if len > CELL_DATA_LEN {
85
                return Err(Error::Internal(internal!("ran out of space for cell")));
86
70
            }
87
            // pad to end of fixed-length cell
88
70
            dst.write_zeros(CELL_DATA_LEN - len);
89
        }
90
86
        Ok(())
91
86
    }
92

            
93
    /// Try to decode a cell from the provided BytesMut object.
94
    ///
95
    /// On a definite decoding error, return Err(_).  On a cell that might
96
    /// just be truncated, return Ok(None).
97
984
    pub fn decode_cell<M: ChanMsg>(
98
984
        &mut self,
99
984
        src: &mut BytesMut,
100
984
    ) -> crate::Result<Option<ChanCell<M>>> {
101
        /// Wrap `be` as an appropriate type.
102
208
        fn wrap_err(be: tor_bytes::Error) -> crate::Error {
103
208
            crate::Error::BytesErr {
104
208
                err: be,
105
208
                parsed: "channel cell",
106
208
            }
107
208
        }
108

            
109
984
        if src.len() < 7 {
110
            // Smallest possible command: varcell with len 0
111
196
            return Ok(None);
112
788
        }
113
788
        let cmd: ChanCmd = src[4].into();
114
788
        let varcell = cmd.is_var_cell();
115
788
        let cell_len: usize = if varcell {
116
540
            let msg_len = u16::from_be_bytes(
117
540
                src[5..7]
118
540
                    .try_into()
119
540
                    .expect("Two-byte slice was not two bytes long!?"),
120
            );
121
540
            msg_len as usize + 7
122
        } else {
123
248
            514
124
        };
125
788
        if src.len() < cell_len {
126
508
            return Ok(None);
127
280
        }
128

            
129
280
        let cell = src.split_to(cell_len).freeze();
130
        //trace!("{:?} cell body ({}) is {:?}", cmd, cell.len(), &cell[..]);
131
280
        let mut r = Reader::from_bytes(&cell);
132
280
        let circid: Option<CircId> = CircId::new(r.take_u32().map_err(wrap_err)?);
133
280
        r.advance(if varcell { 3 } else { 1 }).map_err(wrap_err)?;
134
280
        let msg = M::decode_from_reader(cmd, &mut r).map_err(wrap_err)?;
135

            
136
272
        if !cmd.accepts_circid_val(circid) {
137
4
            return Err(Error::ChanProto(format!(
138
4
                "Invalid circuit ID {} for cell command {}",
139
4
                CircId::get_or_zero(circid),
140
4
                cmd
141
4
            )));
142
268
        }
143
268
        Ok(Some(ChanCell { circid, msg }))
144
984
    }
145
}