erbium_net/
raw.rs

1/*   Copyright 2023 Perry Lorier
2 *
3 *  Licensed under the Apache License, Version 2.0 (the "License");
4 *  you may not use this file except in compliance with the License.
5 *  You may obtain a copy of the License at
6 *
7 *      http://www.apache.org/licenses/LICENSE-2.0
8 *
9 *  Unless required by applicable law or agreed to in writing, software
10 *  distributed under the License is distributed on an "AS IS" BASIS,
11 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 *  See the License for the specific language governing permissions and
13 *  limitations under the License.
14 *
15 *  SPDX-License-Identifier: Apache-2.0
16 *
17 *  Low level functions to create/use an async raw socket.
18 */
19
20use nix::sys::socket;
21use std::io;
22use std::os::unix::io::AsRawFd;
23use std::os::unix::io::RawFd;
24use tokio::io::unix::AsyncFd;
25
26use crate::{addr::NetAddr, udp};
27use nix::libc;
28
29pub type Error = std::io::Error;
30pub type Result<T> = std::result::Result<T, Error>;
31pub type MsgFlags = socket::MsgFlags;
32pub use std::io::{IoSlice, IoSliceMut};
33
34/* These should be refactored out somewhere */
35pub type ControlMessage = udp::ControlMessage;
36
37#[derive(Copy, Clone)]
38pub struct IpProto(u8);
39impl IpProto {
40    pub const ICMP: IpProto = IpProto(1);
41    pub const TCP: IpProto = IpProto(6);
42    pub const UDP: IpProto = IpProto(17);
43    pub const ICMP6: IpProto = IpProto(58);
44}
45
46impl From<IpProto> for u8 {
47    fn from(ipp: IpProto) -> Self {
48        ipp.0
49    }
50}
51
52impl From<IpProto> for u16 {
53    fn from(ipp: IpProto) -> Self {
54        ipp.0 as u16
55    }
56}
57
58#[derive(Copy, Clone)]
59pub struct EthProto(u16);
60impl EthProto {
61    pub const IP4: EthProto = EthProto(0x0800);
62    pub const ALL: EthProto = EthProto(0x0003);
63    pub const LLDP: EthProto = EthProto(0x88cc);
64}
65
66#[derive(Debug)]
67pub struct RawSocket {
68    fd: AsyncFd<crate::socket::SocketFd>,
69}
70
71impl AsRawFd for RawSocket {
72    fn as_raw_fd(&self) -> RawFd {
73        self.fd.as_raw_fd()
74    }
75}
76
77impl RawSocket {
78    pub fn new(protocol: EthProto) -> Result<Self> {
79        Ok(Self {
80            fd: AsyncFd::new(crate::socket::new_socket(
81                libc::AF_PACKET,
82                libc::SOCK_RAW,
83                protocol.0.to_be() as libc::c_int,
84            )?)?,
85        })
86    }
87
88    #[allow(dead_code)]
89    pub fn send(&self, buf: &[u8], flags: MsgFlags) -> Result<usize> {
90        socket::send(self.as_raw_fd(), buf, flags).map_err(|e| e.into())
91    }
92
93    pub async fn recv_msg(
94        &self,
95        bufsize: usize,
96        flags: MsgFlags,
97    ) -> io::Result<crate::socket::RecvMsg> {
98        crate::socket::recv_msg(&self.fd, bufsize, flags).await
99    }
100
101    pub async fn send_msg(
102        &self,
103        buffer: &[u8],
104        cmsg: &ControlMessage,
105        flags: MsgFlags,
106        addr: Option<&NetAddr>,
107    ) -> io::Result<()> {
108        crate::socket::send_msg(&self.fd, buffer, cmsg, flags, addr).await
109    }
110
111    pub fn set_socket_option<O: nix::sys::socket::SetSockOpt>(
112        &self,
113        opt: O,
114        val: &O::Val,
115    ) -> Result<()> {
116        nix::sys::socket::setsockopt(self.as_raw_fd(), opt, val).map_err(|e| e.into())
117    }
118}
119
120#[derive(Debug)]
121pub struct CookedRawSocket {
122    fd: AsyncFd<crate::socket::SocketFd>,
123}
124
125impl AsRawFd for CookedRawSocket {
126    fn as_raw_fd(&self) -> RawFd {
127        self.fd.as_raw_fd()
128    }
129}
130
131impl CookedRawSocket {
132    pub fn new(protocol: EthProto) -> Result<Self> {
133        Ok(Self {
134            fd: AsyncFd::new(crate::socket::new_socket(
135                libc::AF_PACKET,
136                libc::SOCK_RAW,
137                protocol.0 as libc::c_int,
138            )?)?,
139        })
140    }
141
142    #[allow(dead_code)]
143    pub fn send(&self, buf: &[u8], flags: MsgFlags) -> Result<usize> {
144        socket::send(self.as_raw_fd(), buf, flags).map_err(|e| e.into())
145    }
146
147    pub async fn recv_msg(
148        &self,
149        bufsize: usize,
150        flags: MsgFlags,
151    ) -> io::Result<crate::socket::RecvMsg> {
152        crate::socket::recv_msg(&self.fd, bufsize, flags).await
153    }
154
155    pub async fn send_msg(
156        &self,
157        buffer: &[u8],
158        cmsg: &ControlMessage,
159        flags: MsgFlags,
160        addr: Option<&NetAddr>,
161    ) -> io::Result<()> {
162        crate::socket::send_msg(&self.fd, buffer, cmsg, flags, addr).await
163    }
164
165    pub fn set_socket_option<O: nix::sys::socket::SetSockOpt>(
166        &self,
167        opt: O,
168        val: &O::Val,
169    ) -> Result<()> {
170        nix::sys::socket::setsockopt(self.as_raw_fd(), opt, val).map_err(|e| e.into())
171    }
172}
173
174#[derive(Debug)]
175pub struct Raw6Socket {
176    fd: AsyncFd<crate::socket::SocketFd>,
177}
178
179impl AsRawFd for Raw6Socket {
180    fn as_raw_fd(&self) -> RawFd {
181        self.fd.as_raw_fd()
182    }
183}
184
185impl Raw6Socket {
186    pub fn new(protocol: IpProto) -> Result<Self> {
187        Ok(Self {
188            fd: AsyncFd::new(crate::socket::new_socket(
189                libc::AF_INET6,
190                libc::SOCK_RAW,
191                protocol.0 as libc::c_int,
192            )?)?,
193        })
194    }
195
196    #[allow(dead_code)]
197    pub fn send(&self, buf: &[u8], flags: MsgFlags) -> Result<usize> {
198        socket::send(self.as_raw_fd(), buf, flags).map_err(|e| e.into())
199    }
200
201    pub async fn recv_msg(
202        &self,
203        bufsize: usize,
204        flags: MsgFlags,
205    ) -> io::Result<crate::socket::RecvMsg> {
206        crate::socket::recv_msg(&self.fd, bufsize, flags).await
207    }
208
209    pub async fn send_msg(
210        &self,
211        buffer: &[u8],
212        cmsg: &ControlMessage,
213        flags: MsgFlags,
214        addr: Option<&NetAddr>,
215    ) -> io::Result<()> {
216        crate::socket::send_msg(&self.fd, buffer, cmsg, flags, addr).await
217    }
218
219    pub fn set_socket_option<O: nix::sys::socket::SetSockOpt>(
220        &self,
221        opt: O,
222        val: &O::Val,
223    ) -> Result<()> {
224        nix::sys::socket::setsockopt(self.as_raw_fd(), opt, val).map_err(|e| e.into())
225    }
226}
227
228#[derive(Debug)]
229pub struct Raw4Socket {
230    fd: AsyncFd<crate::socket::SocketFd>,
231}
232
233impl AsRawFd for Raw4Socket {
234    fn as_raw_fd(&self) -> RawFd {
235        self.fd.as_raw_fd()
236    }
237}
238
239impl Raw4Socket {
240    pub fn new(protocol: IpProto) -> Result<Self> {
241        Ok(Self {
242            fd: AsyncFd::new(crate::socket::new_socket(
243                libc::AF_INET,
244                libc::SOCK_RAW,
245                protocol.0 as libc::c_int,
246            )?)?,
247        })
248    }
249
250    #[allow(dead_code)]
251    pub fn send(&self, buf: &[u8], flags: MsgFlags) -> Result<usize> {
252        socket::send(self.as_raw_fd(), buf, flags).map_err(|e| e.into())
253    }
254
255    pub async fn recv_msg(
256        &self,
257        bufsize: usize,
258        flags: MsgFlags,
259    ) -> io::Result<crate::socket::RecvMsg> {
260        crate::socket::recv_msg(&self.fd, bufsize, flags).await
261    }
262
263    pub async fn send_msg(
264        &self,
265        buffer: &[u8],
266        cmsg: &ControlMessage,
267        flags: MsgFlags,
268        addr: Option<&NetAddr>,
269    ) -> io::Result<()> {
270        crate::socket::send_msg(&self.fd, buffer, cmsg, flags, addr).await
271    }
272
273    pub fn set_socket_option<O: nix::sys::socket::SetSockOpt>(
274        fd: RawFd,
275        opt: O,
276        val: &O::Val,
277    ) -> Result<()> {
278        nix::sys::socket::setsockopt(fd, opt, val).map_err(|e| e.into())
279    }
280}