1
use std::{convert::TryFrom, net::IpAddr, ptr};
2

            
3
use bitflags::bitflags;
4

            
5
#[cfg(target_os = "windows")]
6
use windows_sys::Win32::Networking::WinSock;
7

            
8
use crate::{
9
    capture::{Active, Capture},
10
    cstr_to_string, raw, Error,
11
};
12

            
13
bitflags! {
14
    /// Network device flags.
15
    pub struct IfFlags: u32 {
16
        /// Set if the device is a loopback interface
17
        const LOOPBACK = raw::PCAP_IF_LOOPBACK;
18
        /// Set if the device is up
19
        const UP = raw::PCAP_IF_UP;
20
        /// Set if the device is running
21
        const RUNNING = raw::PCAP_IF_RUNNING;
22
        /// Set if the device is a wireless interface; this includes IrDA as well as radio-based
23
        /// networks such as IEEE 802.15.4 and IEEE 802.11, so it doesn't just mean Wi-Fi
24
        const WIRELESS = raw::PCAP_IF_WIRELESS;
25
    }
26
}
27

            
28
impl From<u32> for IfFlags {
29
8
    fn from(flags: u32) -> Self {
30
8
        IfFlags::from_bits_truncate(flags)
31
8
    }
32
}
33

            
34
#[derive(Debug, Clone, PartialEq, Eq)]
35
/// Indication of whether the adapter is connected or not; for wireless interfaces, "connected"
36
/// means "associated with a network".
37
pub enum ConnectionStatus {
38
    /// It's unknown whether the adapter is connected or not
39
    Unknown,
40
    /// The adapter is connected
41
    Connected,
42
    /// The adapter is disconnected
43
    Disconnected,
44
    /// The notion of "connected" and "disconnected" don't apply to this interface; for example, it
45
    /// doesn't apply to a loopback device
46
    NotApplicable,
47
}
48

            
49
impl From<u32> for ConnectionStatus {
50
16
    fn from(flags: u32) -> Self {
51
16
        match flags & raw::PCAP_IF_CONNECTION_STATUS {
52
8
            raw::PCAP_IF_CONNECTION_STATUS_UNKNOWN => ConnectionStatus::Unknown,
53
2
            raw::PCAP_IF_CONNECTION_STATUS_CONNECTED => ConnectionStatus::Connected,
54
2
            raw::PCAP_IF_CONNECTION_STATUS_DISCONNECTED => ConnectionStatus::Disconnected,
55
4
            raw::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE => ConnectionStatus::NotApplicable,
56
            // DeviceFlags::CONNECTION_STATUS should be a 2-bit mask which means that the four
57
            // values should cover all the possibilities.
58
            // GRCOV_EXCL_START
59
            _ => unreachable!(),
60
            // GRCOV_EXCL_STOP
61
        }
62
16
    }
63
}
64

            
65
#[derive(Debug, Clone)]
66
pub struct DeviceFlags {
67
    pub if_flags: IfFlags,
68
    pub connection_status: ConnectionStatus,
69
}
70

            
71
impl From<u32> for DeviceFlags {
72
8
    fn from(flags: u32) -> Self {
73
8
        DeviceFlags {
74
8
            if_flags: flags.into(),
75
8
            connection_status: flags.into(),
76
8
        }
77
8
    }
78
}
79

            
80
impl DeviceFlags {
81
6
    pub fn empty() -> Self {
82
6
        DeviceFlags {
83
6
            if_flags: IfFlags::empty(),
84
6
            connection_status: ConnectionStatus::Unknown,
85
6
        }
86
6
    }
87

            
88
10
    pub fn contains(&self, if_flags: IfFlags) -> bool {
89
10
        self.if_flags.contains(if_flags)
90
10
    }
91

            
92
2
    pub fn is_loopback(&self) -> bool {
93
2
        self.contains(IfFlags::LOOPBACK)
94
2
    }
95

            
96
2
    pub fn is_up(&self) -> bool {
97
2
        self.contains(IfFlags::UP)
98
2
    }
99

            
100
2
    pub fn is_running(&self) -> bool {
101
2
        self.contains(IfFlags::RUNNING)
102
2
    }
103

            
104
2
    pub fn is_wireless(&self) -> bool {
105
2
        self.contains(IfFlags::WIRELESS)
106
2
    }
107
}
108

            
109
#[derive(Debug, Clone)]
110
/// A network device name and pcap's description of it.
111
pub struct Device {
112
    /// The name of the interface
113
    pub name: String,
114
    /// A textual description of the interface, if available
115
    pub desc: Option<String>,
116
    /// Addresses associated with this interface
117
    pub addresses: Vec<Address>,
118
    /// Interface flags
119
    pub flags: DeviceFlags,
120
}
121

            
122
impl Device {
123
12
    fn new(
124
12
        name: String,
125
12
        desc: Option<String>,
126
12
        addresses: Vec<Address>,
127
12
        flags: DeviceFlags,
128
12
    ) -> Device {
129
12
        Device {
130
12
            name,
131
12
            desc,
132
12
            addresses,
133
12
            flags,
134
12
        }
135
12
    }
136

            
137
    /// Opens a `Capture<Active>` on this device.
138
2
    pub fn open(self) -> Result<Capture<Active>, Error> {
139
2
        Capture::from_device(self)?.open()
140
2
    }
141

            
142
    /// Returns the default Device suitable for captures according to pcap_findalldevs,
143
    /// or an error from pcap. Note that there may be no suitable devices.
144
6
    pub fn lookup() -> Result<Option<Device>, Error> {
145
6
        unsafe {
146
8
            Device::with_all_devs(|all_devs| {
147
4
                let dev = all_devs;
148
4
                Ok(if !dev.is_null() {
149
2
                    Some(Device::try_from(&*dev)?)
150
                } else {
151
2
                    None
152
                })
153
8
            })
154
6
        }
155
6
    }
156

            
157
    /// Returns a vector of `Device`s known by pcap via pcap_findalldevs.
158
6
    pub fn list() -> Result<Vec<Device>, Error> {
159
6
        unsafe {
160
8
            Device::with_all_devs(|all_devs| {
161
4
                let mut devices = vec![];
162
4
                let mut dev = all_devs;
163
8
                while !dev.is_null() {
164
4
                    devices.push(Device::try_from(&*dev)?);
165
4
                    dev = (*dev).next;
166
                }
167
4
                Ok(devices)
168
8
            })
169
6
        }
170
6
    }
171

            
172
12
    unsafe fn with_all_devs<T, F>(func: F) -> Result<T, Error>
173
12
    where
174
12
        F: FnOnce(*mut raw::pcap_if_t) -> Result<T, Error>,
175
12
    {
176
12
        let all_devs = Error::with_errbuf(|err| {
177
12
            let mut all_devs: *mut raw::pcap_if_t = ptr::null_mut();
178
12
            if raw::pcap_findalldevs(&mut all_devs, err) != 0 {
179
4
                return Err(Error::new(err));
180
8
            }
181
8
            Ok(all_devs)
182
12
        })?;
183
8
        let result = func(all_devs);
184
8
        raw::pcap_freealldevs(all_devs);
185
8
        result
186
12
    }
187
}
188

            
189
impl From<&str> for Device {
190
6
    fn from(name: &str) -> Self {
191
6
        Device::new(name.into(), None, Vec::new(), DeviceFlags::empty())
192
6
    }
193
}
194

            
195
impl TryFrom<&raw::pcap_if_t> for Device {
196
    type Error = Error;
197

            
198
6
    fn try_from(dev: &raw::pcap_if_t) -> Result<Self, Error> {
199
6
        Ok(Device::new(
200
6
            unsafe { cstr_to_string(dev.name)?.ok_or(Error::InvalidString)? },
201
6
            unsafe { cstr_to_string(dev.description)? },
202
6
            unsafe { Address::new_vec(dev.addresses) },
203
6
            DeviceFlags::from(dev.flags),
204
        ))
205
6
    }
206
}
207

            
208
#[derive(Debug, Clone)]
209
/// Address information for an interface
210
pub struct Address {
211
    /// The address
212
    pub addr: IpAddr,
213
    /// Network mask for this address
214
    pub netmask: Option<IpAddr>,
215
    /// Broadcast address for this address
216
    pub broadcast_addr: Option<IpAddr>,
217
    /// P2P destination address for this address
218
    pub dst_addr: Option<IpAddr>,
219
}
220

            
221
impl Address {
222
6
    unsafe fn new_vec(mut ptr: *const raw::pcap_addr_t) -> Vec<Address> {
223
6
        let mut vec = Vec::new();
224
12
        while !ptr.is_null() {
225
6
            if let Some(addr) = Address::new(ptr) {
226
6
                vec.push(addr);
227
6
            }
228
6
            ptr = (*ptr).next;
229
        }
230
6
        vec
231
6
    }
232

            
233
12
    unsafe fn new(ptr: *const raw::pcap_addr_t) -> Option<Address> {
234
17
        Self::convert_sockaddr((*ptr).addr).map(|addr| Address {
235
10
            addr,
236
10
            netmask: Self::convert_sockaddr((*ptr).netmask),
237
10
            broadcast_addr: Self::convert_sockaddr((*ptr).broadaddr),
238
10
            dst_addr: Self::convert_sockaddr((*ptr).dstaddr),
239
17
        })
240
12
    }
241

            
242
    #[cfg(not(windows))]
243
42
    unsafe fn convert_sockaddr(ptr: *const libc::sockaddr) -> Option<IpAddr> {
244
42
        if ptr.is_null() {
245
30
            return None;
246
12
        }
247
12

            
248
12
        match (*ptr).sa_family as i32 {
249
            libc::AF_INET => {
250
6
                let ptr: *const libc::sockaddr_in = std::mem::transmute(ptr);
251
6
                Some(IpAddr::V4(u32::from_be((*ptr).sin_addr.s_addr).into()))
252
            }
253

            
254
            libc::AF_INET6 => {
255
4
                let ptr: *const libc::sockaddr_in6 = std::mem::transmute(ptr);
256
4
                Some(IpAddr::V6((*ptr).sin6_addr.s6_addr.into()))
257
            }
258

            
259
2
            _ => None,
260
        }
261
42
    }
262

            
263
    #[cfg(windows)]
264
    unsafe fn convert_sockaddr(ptr: *const libc::sockaddr) -> Option<IpAddr> {
265
        if ptr.is_null() {
266
            return None;
267
        }
268

            
269
        match (*ptr).sa_family as u32 {
270
            WinSock::AF_INET => {
271
                let ptr: *const WinSock::SOCKADDR_IN = std::mem::transmute(ptr);
272
                let addr: [u8; 4] = ((*ptr).sin_addr.S_un.S_addr).to_ne_bytes();
273
                Some(IpAddr::from(addr))
274
            }
275
            WinSock::AF_INET6 => {
276
                let ptr: *const WinSock::SOCKADDR_IN6 = std::mem::transmute(ptr);
277
                let addr = (*ptr).sin6_addr.u.Byte;
278
                Some(IpAddr::from(addr))
279
            }
280

            
281
            _ => None,
282
        }
283
    }
284
}
285

            
286
#[cfg(test)]
287
mod tests {
288
    use std::ffi::CString;
289

            
290
    use crate::raw::testmod::{as_pcap_t, RAWMTX};
291

            
292
    use super::*;
293

            
294
    #[cfg(not(windows))]
295
    enum Sockaddr {
296
        SockaddrIn(libc::sockaddr_in),
297
        SockaddrIn6(libc::sockaddr_in6),
298
    }
299

            
300
    #[cfg(windows)]
301
    enum Sockaddr {
302
        SockaddrIn(WinSock::SOCKADDR_IN),
303
        SockaddrIn6(WinSock::SOCKADDR_IN6),
304
    }
305

            
306
    impl Sockaddr {
307
        fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
308
            match self {
309
                Sockaddr::SockaddrIn(ref mut sin) => sin as *mut _ as _,
310
                Sockaddr::SockaddrIn6(ref mut sin6) => sin6 as *mut _ as _,
311
            }
312
        }
313

            
314
        fn set_family(&mut self, family: u16) {
315
            // Annoyingly this differs between Linux (u16) and Mac (u8).
316
            #[cfg(not(windows))]
317
            let family = family as libc::sa_family_t;
318

            
319
            match self {
320
                Sockaddr::SockaddrIn(ref mut sin) => sin.sin_family = family,
321
                Sockaddr::SockaddrIn6(ref mut sin6) => sin6.sin6_family = family,
322
            }
323
        }
324
    }
325

            
326
    static IF1_NAME: &str = "if1";
327
    static IF2_NAME: &str = "if2";
328
    static IF1_DESC: &str = "if1 desc";
329
    static IF2_DESC: &str = "if2 desc";
330

            
331
    fn devs() -> Vec<raw::pcap_if_t> {
332
        let mut devs = vec![
333
            raw::pcap_if_t {
334
                next: std::ptr::null_mut(),
335
                name: CString::new(IF1_NAME).unwrap().into_raw(),
336
                description: CString::new(IF1_DESC).unwrap().into_raw(),
337
                addresses: std::ptr::null_mut(),
338
                flags: (raw::PCAP_IF_LOOPBACK | raw::PCAP_IF_UP),
339
            },
340
            raw::pcap_if_t {
341
                next: std::ptr::null_mut(),
342
                name: CString::new(IF2_NAME).unwrap().into_raw(),
343
                description: CString::new(IF2_DESC).unwrap().into_raw(),
344
                addresses: std::ptr::null_mut(),
345
                flags: 0,
346
            },
347
        ];
348
        devs[0].next = &mut devs[1];
349
        devs
350
    }
351

            
352
    trait InetAddressV4 {
353
        fn new() -> Self;
354
        fn set_addr(&mut self, addr: u32);
355
    }
356

            
357
    #[cfg(not(windows))]
358
    impl InetAddressV4 for libc::sockaddr_in {
359
        fn new() -> Self {
360
            let mut addr: Self = unsafe { std::mem::zeroed() };
361
            addr.sin_family = libc::AF_INET as libc::sa_family_t;
362
            addr
363
        }
364

            
365
        fn set_addr(&mut self, addr: u32) {
366
            self.sin_addr.s_addr = addr;
367
        }
368
    }
369

            
370
    #[cfg(windows)]
371
    impl InetAddressV4 for WinSock::SOCKADDR_IN {
372
        fn new() -> Self {
373
            let mut addr: Self = unsafe { std::mem::zeroed() };
374
            // The cast is only necessary due to a bug in windows_sys@v0.36.1
375
            addr.sin_family = WinSock::AF_INET as u16;
376
            addr
377
        }
378

            
379
        fn set_addr(&mut self, addr: u32) {
380
            self.sin_addr.S_un.S_addr = addr;
381
        }
382
    }
383

            
384
    fn sockaddr_ipv4() -> Sockaddr {
385
        #[cfg(not(windows))]
386
        let mut addr: libc::sockaddr_in = InetAddressV4::new();
387
        #[cfg(windows)]
388
        let mut addr: WinSock::SOCKADDR_IN = InetAddressV4::new();
389

            
390
        addr.sin_port = 1075;
391
        addr.set_addr(0x0A000042_u32.to_be());
392

            
393
        Sockaddr::SockaddrIn(addr)
394
    }
395

            
396
    trait InetAddressV6 {
397
        fn new() -> Self;
398
        fn set_octet(&mut self, index: usize, octet: u8);
399
    }
400

            
401
    #[cfg(not(windows))]
402
    impl InetAddressV6 for libc::sockaddr_in6 {
403
        fn new() -> Self {
404
            let mut addr: Self = unsafe { std::mem::zeroed() };
405
            addr.sin6_family = libc::AF_INET6 as libc::sa_family_t;
406
            addr.sin6_addr.s6_addr[0] = 0xFE;
407
            addr.sin6_addr.s6_addr[1] = 0x80;
408
            addr
409
        }
410

            
411
        fn set_octet(&mut self, index: usize, octet: u8) {
412
            self.sin6_addr.s6_addr[index] = octet;
413
        }
414
    }
415

            
416
    #[cfg(windows)]
417
    impl InetAddressV6 for WinSock::SOCKADDR_IN6 {
418
        fn new() -> Self {
419
            let mut addr: Self = unsafe { std::mem::zeroed() };
420
            // The cast is only necessary due to a bug in windows_sys@v0.36.1
421
            addr.sin6_family = WinSock::AF_INET6 as u16;
422
            unsafe {
423
                addr.sin6_addr.u.Byte[0] = 0xFE;
424
                addr.sin6_addr.u.Byte[1] = 0x80;
425
            }
426
            addr
427
        }
428

            
429
        fn set_octet(&mut self, index: usize, octet: u8) {
430
            unsafe { self.sin6_addr.u.Byte[index] = octet };
431
        }
432
    }
433

            
434
    fn sockaddr_ipv6() -> Sockaddr {
435
        #[cfg(not(windows))]
436
        let mut addr: libc::sockaddr_in6 = InetAddressV6::new();
437
        #[cfg(windows)]
438
        let mut addr: WinSock::SOCKADDR_IN6 = InetAddressV6::new();
439

            
440
        addr.sin6_port = 1075;
441
        addr.set_octet(15, 0x42);
442

            
443
        Sockaddr::SockaddrIn6(addr)
444
    }
445

            
446
    impl From<&mut Sockaddr> for raw::pcap_addr_t {
447
        fn from(value: &mut Sockaddr) -> Self {
448
            raw::pcap_addr_t {
449
                next: std::ptr::null_mut(),
450
                addr: value.as_mut_ptr(),
451
                netmask: std::ptr::null_mut(),
452
                broadaddr: std::ptr::null_mut(),
453
                dstaddr: std::ptr::null_mut(),
454
            }
455
        }
456
    }
457

            
458
    #[test]
459
    fn test_device_flags() {
460
        let flags = DeviceFlags::from(
461
            raw::PCAP_IF_LOOPBACK | raw::PCAP_IF_UP | raw::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
462
        );
463

            
464
        assert!(flags.is_loopback());
465
        assert!(flags.is_up());
466
        assert!(flags.contains(IfFlags::LOOPBACK | IfFlags::UP));
467

            
468
        assert!(!flags.is_running());
469
        assert!(!flags.is_wireless());
470

            
471
        assert_ne!(flags.connection_status, ConnectionStatus::Unknown);
472
        assert_ne!(flags.connection_status, ConnectionStatus::Connected);
473
        assert_ne!(flags.connection_status, ConnectionStatus::Disconnected);
474
        assert_eq!(flags.connection_status, ConnectionStatus::NotApplicable);
475

            
476
        assert!(!format!("{:?}", flags).is_empty());
477
    }
478

            
479
    #[test]
480
    fn test_connection_status() {
481
        let flags = raw::PCAP_IF_CONNECTION_STATUS_UNKNOWN;
482
        assert_eq!(ConnectionStatus::from(flags), ConnectionStatus::Unknown);
483

            
484
        let flags = raw::PCAP_IF_CONNECTION_STATUS_CONNECTED;
485
        assert_eq!(ConnectionStatus::from(flags), ConnectionStatus::Connected);
486

            
487
        let flags = raw::PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
488
        assert_eq!(
489
            ConnectionStatus::from(flags),
490
            ConnectionStatus::Disconnected
491
        );
492

            
493
        let flags = raw::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
494
        assert_eq!(
495
            ConnectionStatus::from(flags),
496
            ConnectionStatus::NotApplicable
497
        );
498
    }
499

            
500
    #[test]
501
    fn test_into_capture() {
502
        let _m = RAWMTX.lock();
503

            
504
        let mut dummy: isize = 777;
505
        let pcap = as_pcap_t(&mut dummy);
506

            
507
        let ctx = raw::pcap_create_context();
508
        ctx.expect().return_once_st(move |_, _| pcap);
509

            
510
        let ctx = raw::pcap_activate_context();
511
        ctx.expect()
512
            .withf_st(move |arg1| *arg1 == pcap)
513
            .return_once(|_| 0);
514

            
515
        let ctx = raw::pcap_close_context();
516
        ctx.expect()
517
            .withf_st(move |ptr| *ptr == pcap)
518
            .return_once(|_| {});
519

            
520
        let device: Device = "device".into();
521
        let _capture: Capture<Active> = device.clone().open().unwrap();
522

            
523
        assert!(!format!("{:?}", device).is_empty());
524
    }
525

            
526
    #[test]
527
    fn test_lookup() {
528
        let _m = RAWMTX.lock();
529

            
530
        let ctx = raw::pcap_findalldevs_context();
531
        ctx.expect().return_once_st(move |arg1, _| {
532
            unsafe { *arg1 = std::ptr::null_mut() };
533
            0
534
        });
535

            
536
        let ctx = raw::pcap_freealldevs_context();
537
        ctx.expect().return_once(move |_| {});
538

            
539
        let device = Device::lookup().unwrap();
540
        assert!(device.is_none());
541

            
542
        let mut devs = devs();
543
        let mut addrs = sockaddr_ipv4();
544
        let mut pcap_addr = (&mut addrs).into();
545
        devs[0].addresses = &mut pcap_addr;
546
        let devs_ptr = devs.as_mut_ptr();
547

            
548
        let ctx = raw::pcap_findalldevs_context();
549
        ctx.checkpoint();
550
        ctx.expect().return_once_st(move |arg1, _| {
551
            unsafe { *arg1 = devs_ptr };
552
            0
553
        });
554

            
555
        let ctx = raw::pcap_freealldevs_context();
556
        ctx.checkpoint();
557
        ctx.expect().return_once(move |_| {});
558

            
559
        let device = Device::lookup().unwrap().unwrap();
560
        assert_eq!(&device.name, IF1_NAME);
561
        assert_eq!(&device.desc.unwrap(), IF1_DESC);
562
        assert_eq!(device.addresses.len(), 1);
563
        assert!(device.addresses[0].addr.is_ipv4());
564

            
565
        let ctx = raw::pcap_findalldevs_context();
566
        ctx.checkpoint();
567
        ctx.expect().return_once_st(move |_, _| -1);
568

            
569
        let ctx = raw::pcap_freealldevs_context();
570
        ctx.checkpoint();
571

            
572
        let result = Device::lookup();
573
        assert!(result.is_err());
574
    }
575

            
576
    #[test]
577
    fn test_list() {
578
        let _m = RAWMTX.lock();
579

            
580
        let ctx = raw::pcap_findalldevs_context();
581
        ctx.expect().return_once_st(move |arg1, _| {
582
            unsafe { *arg1 = std::ptr::null_mut() };
583
            0
584
        });
585

            
586
        let ctx = raw::pcap_freealldevs_context();
587
        ctx.expect().return_once(move |_| {});
588

            
589
        let devices = Device::list().unwrap();
590
        assert!(devices.is_empty());
591

            
592
        let mut devs = devs();
593
        let mut ipv4s = sockaddr_ipv4();
594
        let mut ipv6s = sockaddr_ipv6();
595
        let mut pcap_addr: raw::pcap_addr_t = (&mut ipv4s).into();
596
        let mut pcap_addr6: raw::pcap_addr_t = (&mut ipv6s).into();
597
        pcap_addr.next = &mut pcap_addr6;
598
        devs[1].addresses = &mut pcap_addr;
599
        let devs_ptr = devs.as_mut_ptr();
600

            
601
        let ctx = raw::pcap_findalldevs_context();
602
        ctx.checkpoint();
603
        ctx.expect().return_once_st(move |arg1, _| {
604
            unsafe { *arg1 = devs_ptr };
605
            0
606
        });
607

            
608
        let ctx = raw::pcap_freealldevs_context();
609
        ctx.checkpoint();
610
        ctx.expect().return_once(move |_| {});
611

            
612
        let devices = Device::list().unwrap();
613
        assert_eq!(devices.len(), devs.len());
614

            
615
        assert_eq!(&devices[0].name, IF1_NAME);
616
        assert_eq!(devices[0].desc.as_ref().unwrap(), IF1_DESC);
617
        assert_eq!(devices[0].addresses.len(), 0);
618

            
619
        assert_eq!(&devices[1].name, IF2_NAME);
620
        assert_eq!(devices[1].desc.as_ref().unwrap(), IF2_DESC);
621
        assert_eq!(devices[1].addresses.len(), 2);
622
        assert!(devices[1].addresses[0].addr.is_ipv4());
623
        assert!(devices[1].addresses[1].addr.is_ipv6());
624

            
625
        let ctx = raw::pcap_findalldevs_context();
626
        ctx.checkpoint();
627
        ctx.expect().return_once_st(move |_, _| -1);
628

            
629
        let ctx = raw::pcap_freealldevs_context();
630
        ctx.checkpoint();
631

            
632
        let result = Device::list();
633
        assert!(result.is_err());
634
    }
635

            
636
    #[test]
637
    fn test_address_ipv4() {
638
        let mut addr = sockaddr_ipv4();
639
        let pcap_addr: raw::pcap_addr_t = (&mut addr).into();
640

            
641
        let address = unsafe { Address::new(&pcap_addr) }.unwrap();
642

            
643
        assert!(address.addr.is_ipv4());
644
        assert_eq!(address.addr.to_string(), "10.0.0.66");
645

            
646
        assert!(address.netmask.is_none());
647
        assert!(address.broadcast_addr.is_none());
648
        assert!(address.dst_addr.is_none());
649

            
650
        assert!(!format!("{:?}", address).is_empty());
651
    }
652

            
653
    #[test]
654
    fn test_address_family() {
655
        let mut addr = sockaddr_ipv4();
656

            
657
        #[cfg(not(windows))]
658
        addr.set_family(libc::AF_IPX as u16);
659
        #[cfg(windows)]
660
        addr.set_family(WinSock::AF_IPX);
661

            
662
        let pcap_addr: raw::pcap_addr_t = (&mut addr).into();
663

            
664
        let address = unsafe { Address::new(&pcap_addr) };
665
        assert!(address.is_none());
666
    }
667

            
668
    #[test]
669
    fn test_address_ipv6() {
670
        let mut addr = sockaddr_ipv6();
671
        let pcap_addr: raw::pcap_addr_t = (&mut addr).into();
672

            
673
        let address = unsafe { Address::new(&pcap_addr) }.unwrap();
674

            
675
        assert!(address.addr.is_ipv6());
676
        assert_eq!(address.addr.to_string(), "fe80::42");
677

            
678
        assert!(address.netmask.is_none());
679
        assert!(address.broadcast_addr.is_none());
680
        assert!(address.dst_addr.is_none());
681

            
682
        assert!(!format!("{:?}", address).is_empty());
683
    }
684
}