procfs_core/net.rs
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
// Don't throw clippy warnings for manual string stripping.
// The suggested fix with `strip_prefix` removes support for Rust 1.33 and 1.38
#![allow(clippy::manual_strip)]
//! Information about the networking layer.
//!
//! This module corresponds to the `/proc/net` directory and contains various information about the
//! networking layer.
use crate::ProcResult;
use crate::{build_internal_error, expect, from_iter, from_str};
use std::collections::HashMap;
use bitflags::bitflags;
use std::io::BufRead;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::{path::PathBuf, str::FromStr};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum TcpState {
Established = 1,
SynSent,
SynRecv,
FinWait1,
FinWait2,
TimeWait,
Close,
CloseWait,
LastAck,
Listen,
Closing,
NewSynRecv,
}
impl TcpState {
pub fn from_u8(num: u8) -> Option<TcpState> {
match num {
0x01 => Some(TcpState::Established),
0x02 => Some(TcpState::SynSent),
0x03 => Some(TcpState::SynRecv),
0x04 => Some(TcpState::FinWait1),
0x05 => Some(TcpState::FinWait2),
0x06 => Some(TcpState::TimeWait),
0x07 => Some(TcpState::Close),
0x08 => Some(TcpState::CloseWait),
0x09 => Some(TcpState::LastAck),
0x0A => Some(TcpState::Listen),
0x0B => Some(TcpState::Closing),
0x0C => Some(TcpState::NewSynRecv),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
TcpState::Established => 0x01,
TcpState::SynSent => 0x02,
TcpState::SynRecv => 0x03,
TcpState::FinWait1 => 0x04,
TcpState::FinWait2 => 0x05,
TcpState::TimeWait => 0x06,
TcpState::Close => 0x07,
TcpState::CloseWait => 0x08,
TcpState::LastAck => 0x09,
TcpState::Listen => 0x0A,
TcpState::Closing => 0x0B,
TcpState::NewSynRecv => 0x0C,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum UdpState {
Established = 1,
Close = 7,
}
impl UdpState {
pub fn from_u8(num: u8) -> Option<UdpState> {
match num {
0x01 => Some(UdpState::Established),
0x07 => Some(UdpState::Close),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
UdpState::Established => 0x01,
UdpState::Close => 0x07,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum UnixState {
UNCONNECTED = 1,
CONNECTING = 2,
CONNECTED = 3,
DISCONNECTING = 4,
}
impl UnixState {
pub fn from_u8(num: u8) -> Option<UnixState> {
match num {
0x01 => Some(UnixState::UNCONNECTED),
0x02 => Some(UnixState::CONNECTING),
0x03 => Some(UnixState::CONNECTED),
0x04 => Some(UnixState::DISCONNECTING),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
UnixState::UNCONNECTED => 0x01,
UnixState::CONNECTING => 0x02,
UnixState::CONNECTED => 0x03,
UnixState::DISCONNECTING => 0x04,
}
}
}
/// An entry in the TCP socket table
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TcpNetEntry {
pub local_address: SocketAddr,
pub remote_address: SocketAddr,
pub state: TcpState,
pub rx_queue: u32,
pub tx_queue: u32,
pub uid: u32,
pub inode: u64,
}
/// An entry in the UDP socket table
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UdpNetEntry {
pub local_address: SocketAddr,
pub remote_address: SocketAddr,
pub state: UdpState,
pub rx_queue: u32,
pub tx_queue: u32,
pub uid: u32,
pub inode: u64,
}
/// An entry in the Unix socket table
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UnixNetEntry {
/// The number of users of the socket
pub ref_count: u32,
/// The socket type.
///
/// Possible values are `SOCK_STREAM`, `SOCK_DGRAM`, or `SOCK_SEQPACKET`. These constants can
/// be found in the libc crate.
pub socket_type: u16,
/// The state of the socket
pub state: UnixState,
/// The inode number of the socket
pub inode: u64,
/// The bound pathname (if any) of the socket.
///
/// Sockets in the abstract namespace are included, and are shown with a path that commences
/// with the '@' character.
pub path: Option<PathBuf>,
}
/// Parses an address in the form 00010203:1234
///
/// Also supports IPv6
fn parse_addressport_str(s: &str, little_endian: bool) -> ProcResult<SocketAddr> {
let mut las = s.split(':');
let ip_part = expect!(las.next(), "ip_part");
let port = expect!(las.next(), "port");
let port = from_str!(u16, port, 16);
use std::convert::TryInto;
let read_u32 = if little_endian {
u32::from_le_bytes
} else {
u32::from_be_bytes
};
if ip_part.len() == 8 {
let bytes = expect!(hex::decode(ip_part));
let ip_u32 = read_u32(bytes[..4].try_into().unwrap());
let ip = Ipv4Addr::from(ip_u32);
Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
} else if ip_part.len() == 32 {
let bytes = expect!(hex::decode(ip_part));
let ip_a = read_u32(bytes[0..4].try_into().unwrap());
let ip_b = read_u32(bytes[4..8].try_into().unwrap());
let ip_c = read_u32(bytes[8..12].try_into().unwrap());
let ip_d = read_u32(bytes[12..16].try_into().unwrap());
let ip = Ipv6Addr::new(
((ip_a >> 16) & 0xffff) as u16,
(ip_a & 0xffff) as u16,
((ip_b >> 16) & 0xffff) as u16,
(ip_b & 0xffff) as u16,
((ip_c >> 16) & 0xffff) as u16,
(ip_c & 0xffff) as u16,
((ip_d >> 16) & 0xffff) as u16,
(ip_d & 0xffff) as u16,
);
Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)))
} else {
Err(build_internal_error!(format!(
"Unable to parse {:?} as an address:port",
s
)))
}
}
/// TCP socket entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TcpNetEntries(pub Vec<TcpNetEntry>);
impl super::FromBufReadSI for TcpNetEntries {
fn from_buf_read<R: BufRead>(r: R, system_info: &crate::SystemInfo) -> ProcResult<Self> {
let mut vec = Vec::new();
// first line is a header we need to skip
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next();
let local_address = expect!(s.next(), "tcp::local_address");
let rem_address = expect!(s.next(), "tcp::rem_address");
let state = expect!(s.next(), "tcp::st");
let mut tx_rx_queue = expect!(s.next(), "tcp::tx_queue:rx_queue").splitn(2, ':');
let tx_queue = from_str!(u32, expect!(tx_rx_queue.next(), "tcp::tx_queue"), 16);
let rx_queue = from_str!(u32, expect!(tx_rx_queue.next(), "tcp::rx_queue"), 16);
s.next(); // skip tr and tm->when
s.next(); // skip retrnsmt
let uid = from_str!(u32, expect!(s.next(), "tcp::uid"));
s.next(); // skip timeout
let inode = expect!(s.next(), "tcp::inode");
vec.push(TcpNetEntry {
local_address: parse_addressport_str(local_address, system_info.is_little_endian())?,
remote_address: parse_addressport_str(rem_address, system_info.is_little_endian())?,
rx_queue,
tx_queue,
state: expect!(TcpState::from_u8(from_str!(u8, state, 16))),
uid,
inode: from_str!(u64, inode),
});
}
Ok(TcpNetEntries(vec))
}
}
/// UDP socket entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UdpNetEntries(pub Vec<UdpNetEntry>);
impl super::FromBufReadSI for UdpNetEntries {
fn from_buf_read<R: BufRead>(r: R, system_info: &crate::SystemInfo) -> ProcResult<Self> {
let mut vec = Vec::new();
// first line is a header we need to skip
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next();
let local_address = expect!(s.next(), "udp::local_address");
let rem_address = expect!(s.next(), "udp::rem_address");
let state = expect!(s.next(), "udp::st");
let mut tx_rx_queue = expect!(s.next(), "udp::tx_queue:rx_queue").splitn(2, ':');
let tx_queue: u32 = from_str!(u32, expect!(tx_rx_queue.next(), "udp::tx_queue"), 16);
let rx_queue: u32 = from_str!(u32, expect!(tx_rx_queue.next(), "udp::rx_queue"), 16);
s.next(); // skip tr and tm->when
s.next(); // skip retrnsmt
let uid = from_str!(u32, expect!(s.next(), "udp::uid"));
s.next(); // skip timeout
let inode = expect!(s.next(), "udp::inode");
vec.push(UdpNetEntry {
local_address: parse_addressport_str(local_address, system_info.is_little_endian())?,
remote_address: parse_addressport_str(rem_address, system_info.is_little_endian())?,
rx_queue,
tx_queue,
state: expect!(UdpState::from_u8(from_str!(u8, state, 16))),
uid,
inode: from_str!(u64, inode),
});
}
Ok(UdpNetEntries(vec))
}
}
/// Unix socket entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UnixNetEntries(pub Vec<UnixNetEntry>);
impl super::FromBufRead for UnixNetEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
// first line is a header we need to skip
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next(); // skip table slot number
let ref_count = from_str!(u32, expect!(s.next()), 16);
s.next(); // skip protocol, always zero
s.next(); // skip internal kernel flags
let socket_type = from_str!(u16, expect!(s.next()), 16);
let state = from_str!(u8, expect!(s.next()), 16);
let inode = from_str!(u64, expect!(s.next()));
let path = s.next().map(PathBuf::from);
vec.push(UnixNetEntry {
ref_count,
socket_type,
inode,
state: expect!(UnixState::from_u8(state)),
path,
});
}
Ok(UnixNetEntries(vec))
}
}
/// An entry in the ARP table
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ARPEntry {
/// IPv4 address
pub ip_address: Ipv4Addr,
/// Hardware type
///
/// This will almost always be ETHER (or maybe INFINIBAND)
pub hw_type: ARPHardware,
/// Internal kernel flags
pub flags: ARPFlags,
/// MAC Address
pub hw_address: Option<[u8; 6]>,
/// Device name
pub device: String,
}
bitflags! {
/// Hardware type for an ARP table entry.
// source: include/uapi/linux/if_arp.h
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct ARPHardware: u32 {
/// NET/ROM pseudo
const NETROM = 0;
/// Ethernet
const ETHER = 1;
/// Experimental ethernet
const EETHER = 2;
/// AX.25 Level 2
const AX25 = 3;
/// PROnet token ring
const PRONET = 4;
/// Chaosnet
const CHAOS = 5;
/// IEEE 802.2 Ethernet/TR/TB
const IEEE802 = 6;
/// Arcnet
const ARCNET = 7;
/// APPLEtalk
const APPLETLK = 8;
/// Frame Relay DLCI
const DLCI = 15;
/// ATM
const ATM = 19;
/// Metricom STRIP
const METRICOM = 23;
//// IEEE 1394 IPv4 - RFC 2734
const IEEE1394 = 24;
/// EUI-64
const EUI64 = 27;
/// InfiniBand
const INFINIBAND = 32;
}
}
bitflags! {
/// Flags for ARP entries
// source: include/uapi/linux/if_arp.h
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct ARPFlags: u32 {
/// Completed entry
const COM = 0x02;
/// Permanent entry
const PERM = 0x04;
/// Publish entry
const PUBL = 0x08;
/// Has requested trailers
const USETRAILERS = 0x10;
/// Want to use a netmask (only for proxy entries)
const NETMASK = 0x20;
// Don't answer this address
const DONTPUB = 0x40;
}
}
/// ARP table entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ArpEntries(pub Vec<ARPEntry>);
impl super::FromBufRead for ArpEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
// First line is a header we need to skip
for line in r.lines().skip(1) {
// Check if there might have been an IO error.
let line = line?;
let mut line = line.split_whitespace();
let ip_address = expect!(Ipv4Addr::from_str(expect!(line.next())));
let hw = from_str!(u32, &expect!(line.next())[2..], 16);
let hw = ARPHardware::from_bits_truncate(hw);
let flags = from_str!(u32, &expect!(line.next())[2..], 16);
let flags = ARPFlags::from_bits_truncate(flags);
let mac = expect!(line.next());
let mut mac: Vec<Result<u8, _>> = mac.split(':').map(|s| Ok(from_str!(u8, s, 16))).collect();
let mac = if mac.len() == 6 {
let mac_block_f = mac.pop().unwrap()?;
let mac_block_e = mac.pop().unwrap()?;
let mac_block_d = mac.pop().unwrap()?;
let mac_block_c = mac.pop().unwrap()?;
let mac_block_b = mac.pop().unwrap()?;
let mac_block_a = mac.pop().unwrap()?;
if mac_block_a == 0
&& mac_block_b == 0
&& mac_block_c == 0
&& mac_block_d == 0
&& mac_block_e == 0
&& mac_block_f == 0
{
None
} else {
Some([
mac_block_a,
mac_block_b,
mac_block_c,
mac_block_d,
mac_block_e,
mac_block_f,
])
}
} else {
None
};
// mask is always "*"
let _mask = expect!(line.next());
let dev = expect!(line.next());
vec.push(ARPEntry {
ip_address,
hw_type: hw,
flags,
hw_address: mac,
device: dev.to_string(),
})
}
Ok(ArpEntries(vec))
}
}
/// General statistics for a network interface/device
///
/// For an example, see the [interface_stats.rs](https://github.com/eminence/procfs/tree/master/examples)
/// example in the source repo.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct DeviceStatus {
/// Name of the interface
pub name: String,
/// Total bytes received
pub recv_bytes: u64,
/// Total packets received
pub recv_packets: u64,
/// Bad packets received
pub recv_errs: u64,
/// Packets dropped
pub recv_drop: u64,
/// Fifo overrun
pub recv_fifo: u64,
/// Frame alignment errors
pub recv_frame: u64,
/// Number of compressed packets received
pub recv_compressed: u64,
/// Number of multicast packets received
pub recv_multicast: u64,
/// Total bytes transmitted
pub sent_bytes: u64,
/// Total packets transmitted
pub sent_packets: u64,
/// Number of transmission errors
pub sent_errs: u64,
/// Number of packets dropped during transmission
pub sent_drop: u64,
pub sent_fifo: u64,
/// Number of collisions
pub sent_colls: u64,
/// Number of packets not sent due to carrier errors
pub sent_carrier: u64,
/// Number of compressed packets transmitted
pub sent_compressed: u64,
}
impl DeviceStatus {
fn from_str(s: &str) -> ProcResult<DeviceStatus> {
let mut split = s.split_whitespace();
let name: String = expect!(from_iter(&mut split));
let recv_bytes = expect!(from_iter(&mut split));
let recv_packets = expect!(from_iter(&mut split));
let recv_errs = expect!(from_iter(&mut split));
let recv_drop = expect!(from_iter(&mut split));
let recv_fifo = expect!(from_iter(&mut split));
let recv_frame = expect!(from_iter(&mut split));
let recv_compressed = expect!(from_iter(&mut split));
let recv_multicast = expect!(from_iter(&mut split));
let sent_bytes = expect!(from_iter(&mut split));
let sent_packets = expect!(from_iter(&mut split));
let sent_errs = expect!(from_iter(&mut split));
let sent_drop = expect!(from_iter(&mut split));
let sent_fifo = expect!(from_iter(&mut split));
let sent_colls = expect!(from_iter(&mut split));
let sent_carrier = expect!(from_iter(&mut split));
let sent_compressed = expect!(from_iter(&mut split));
Ok(DeviceStatus {
name: name.trim_end_matches(':').to_owned(),
recv_bytes,
recv_packets,
recv_errs,
recv_drop,
recv_fifo,
recv_frame,
recv_compressed,
recv_multicast,
sent_bytes,
sent_packets,
sent_errs,
sent_drop,
sent_fifo,
sent_colls,
sent_carrier,
sent_compressed,
})
}
}
/// Device status information for all network interfaces.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct InterfaceDeviceStatus(pub HashMap<String, DeviceStatus>);
impl super::FromBufRead for InterfaceDeviceStatus {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut map = HashMap::new();
// the first two lines are headers, so skip them
for line in r.lines().skip(2) {
let dev = DeviceStatus::from_str(&line?)?;
map.insert(dev.name.clone(), dev);
}
Ok(InterfaceDeviceStatus(map))
}
}
/// An entry in the ipv4 route table
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RouteEntry {
/// Interface to which packets for this route will be sent
pub iface: String,
/// The destination network or destination host
pub destination: Ipv4Addr,
pub gateway: Ipv4Addr,
pub flags: u16,
/// Number of references to this route
pub refcnt: u16,
/// Count of lookups for the route
pub in_use: u16,
/// The 'distance' to the target (usually counted in hops)
pub metrics: u32,
pub mask: Ipv4Addr,
/// Default maximum transmission unit for TCP connections over this route
pub mtu: u32,
/// Default window size for TCP connections over this route
pub window: u32,
/// Initial RTT (Round Trip Time)
pub irtt: u32,
}
/// A set of ipv4 routes.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RouteEntries(pub Vec<RouteEntry>);
impl super::FromBufRead for RouteEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
// First line is a header we need to skip
for line in r.lines().skip(1) {
// Check if there might have been an IO error.
let line = line?;
let mut line = line.split_whitespace();
// network interface name, e.g. eth0
let iface = expect!(line.next());
let destination = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let gateway = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let flags = from_str!(u16, expect!(line.next()), 16);
let refcnt = from_str!(u16, expect!(line.next()), 10);
let in_use = from_str!(u16, expect!(line.next()), 10);
let metrics = from_str!(u32, expect!(line.next()), 10);
let mask = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let mtu = from_str!(u32, expect!(line.next()), 10);
let window = from_str!(u32, expect!(line.next()), 10);
let irtt = from_str!(u32, expect!(line.next()), 10);
vec.push(RouteEntry {
iface: iface.to_string(),
destination,
gateway,
flags,
refcnt,
in_use,
metrics,
mask,
mtu,
window,
irtt,
});
}
Ok(RouteEntries(vec))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
/// The indication of whether this entity is acting as an IP gateway in respect
/// to the forwarding of datagrams received by, but not addressed to, this
/// entity. IP gateways forward datagrams. IP hosts do not (except those
/// source-routed via the host).
///
/// Note that for some managed nodes, this object may take on only a subset of
/// the values possible. Accordingly, it is appropriate for an agent to return a
/// `badValue` response if a management station attempts to change this object
/// to an inappropriate value.
pub enum IpForwarding {
/// Acting as a gateway
Forwarding = 1,
/// Not acting as a gateway
NotForwarding = 2,
}
impl IpForwarding {
pub fn from_u8(num: u8) -> Option<IpForwarding> {
match num {
1 => Some(IpForwarding::Forwarding),
2 => Some(IpForwarding::NotForwarding),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
IpForwarding::Forwarding => 1,
IpForwarding::NotForwarding => 2,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
/// The algorithm used to determine the timeout value used for retransmitting
/// unacknowledged octets.
pub enum TcpRtoAlgorithm {
/// None of the following
Other = 1,
/// A constant rto
Constant = 2,
/// MIL-STD-1778, [Appendix B](https://datatracker.ietf.org/doc/html/rfc1213#appendix-B)
Rsre = 3,
/// Van Jacobson's algorithm
///
/// Reference: Jacobson, V., "Congestion Avoidance and Control", SIGCOMM 1988, Stanford, California.
Vanj = 4,
}
impl TcpRtoAlgorithm {
pub fn from_u8(num: u8) -> Option<TcpRtoAlgorithm> {
match num {
1 => Some(TcpRtoAlgorithm::Other),
2 => Some(TcpRtoAlgorithm::Constant),
3 => Some(TcpRtoAlgorithm::Rsre),
4 => Some(TcpRtoAlgorithm::Vanj),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
TcpRtoAlgorithm::Other => 1,
TcpRtoAlgorithm::Constant => 2,
TcpRtoAlgorithm::Rsre => 3,
TcpRtoAlgorithm::Vanj => 4,
}
}
}
/// This struct holds the data needed for the IP, ICMP, TCP, and UDP management
/// information bases for an SNMP agent.
///
/// For more details, see [RFC1213](https://datatracker.ietf.org/doc/html/rfc1213)
/// and [SNMP counter](https://docs.kernel.org/networking/snmp_counter.html)
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Snmp {
pub ip_forwarding: IpForwarding,
/// The default value inserted into the Time-To-Live field of the IP header
/// of datagrams originated at this entity, whenever a TTL value is not
/// supplied by the transport layer protocol.
pub ip_default_ttl: u32,
/// The total number of input datagrams received from interfaces, including
/// those received in error.
pub ip_in_receives: u64,
/// The number of input datagrams discarded due to errors in their IP
/// headers.
pub ip_in_hdr_errors: u64,
/// The number of input datagrams discarded because the IP address in their
/// IP header's destination field was not a valid address to be received at
/// this entity.
pub ip_in_addr_errors: u64,
/// The number of input datagrams for which this entity was not their final
/// IP destination, as a result of which an attempt was made to find a
/// route to forward them to that final destination.
pub ip_forw_datagrams: u64,
/// The number of locally-addressed datagrams received successfully but
/// discarded because of an unknown or unsupported protocol.
pub ip_in_unknown_protos: u64,
/// The number of input IP datagrams for which no problems were encountered
/// to prevent their continued processing, but which were discarded
/// (e.g., for lack of buffer space).
pub ip_in_discards: u64,
/// The total number of input datagrams successfully delivered to IP
/// user-protocols (including ICMP).
///
/// Note that this counter does not include any datagrams discarded while
/// awaiting re-assembly.
pub ip_in_delivers: u64,
/// The total number of IP datagrams which local IP user-protocols
/// (including ICMP) supplied to IP in requests for transmission.
///
/// Note that this counter does not include any datagrams counted in
/// ipForwDatagrams.
pub ip_out_requests: u64,
/// The number of output IP datagrams for which no problem was encountered
/// to prevent their transmission to their destination, but which were
/// discarded (e.g., for lack of buffer space).
///
/// Note that this counter would include datagrams counted in
/// `IpForwDatagrams` if any such packets met this (discretionary) discard
/// criterion.
pub ip_out_discards: u64,
/// The number of IP datagrams discarded because no route could be found to
/// transmit them to their destination.
///
/// Note that this counter includes any packets counted in `IpForwDatagrams`
/// which meet this `no-route' criterion.
///
/// Note that this includes any datagarms which a host cannot route because
/// all of its default gateways are down.
pub ip_out_no_routes: u64,
/// The maximum number of seconds which received fragments are held while
/// they are awaiting reassembly at this entity.
pub ip_reasm_timeout: u64,
/// The number of IP fragments received which needed to be reassembled at
/// this entity.
pub ip_reasm_reqds: u64,
/// The number of IP datagrams successfully re-assembled.
pub ip_reasm_oks: u64,
/// The number of failures detected by the IP re-assembly algorithm
/// (for whatever reason: timed out, errors, etc).
///
/// Note that this is not necessarily a count of discarded IP fragments
/// since some algorithms (notably the algorithm in [RFC 815](https://datatracker.ietf.org/doc/html/rfc815))
/// can lose track of the number of fragments by combining them as they are
/// received.
pub ip_reasm_fails: u64,
/// The number of IP datagrams that have been successfully fragmented at
/// this entity.
pub ip_frag_oks: u64,
/// The number of IP datagrams that have been discarded because they needed
/// to be fragmented at this entity but could not be, e.g., because their
/// `Don't Fragment` flag was set.
pub ip_frag_fails: u64,
/// The number of IP datagram fragments that have been generated as a result
/// of fragmentation at this entity.
pub ip_frag_creates: u64,
/// The total number of ICMP messages which the entity received.
///
/// Note that this counter includes all those counted by `icmp_in_errors`.
pub icmp_in_msgs: u64,
/// The number of ICMP messages which the entity received but determined as
/// having ICMP-specific errors (bad ICMP checksums, bad length, etc.
pub icmp_in_errors: u64,
/// This counter indicates the checksum of the ICMP packet is wrong.
///
/// Non RFC1213 field
pub icmp_in_csum_errors: u64,
/// The number of ICMP Destination Unreachable messages received.
pub icmp_in_dest_unreachs: u64,
/// The number of ICMP Time Exceeded messages received.
pub icmp_in_time_excds: u64,
/// The number of ICMP Parameter Problem messages received.
pub icmp_in_parm_probs: u64,
/// The number of ICMP Source Quench messages received.
pub icmp_in_src_quenchs: u64,
/// The number of ICMP Redirect messages received.
pub icmp_in_redirects: u64,
/// The number of ICMP Echo (request) messages received.
pub icmp_in_echos: u64,
/// The number of ICMP Echo Reply messages received.
pub icmp_in_echo_reps: u64,
/// The number of ICMP Timestamp (request) messages received.
pub icmp_in_timestamps: u64,
/// The number of ICMP Timestamp Reply messages received.
pub icmp_in_timestamp_reps: u64,
/// The number of ICMP Address Mask Request messages received.
pub icmp_in_addr_masks: u64,
/// The number of ICMP Address Mask Reply messages received.
pub icmp_in_addr_mask_reps: u64,
/// The total number of ICMP messages which this entity attempted to send.
///
/// Note that this counter includes all those counted by `icmp_out_errors`.
pub icmp_out_msgs: u64,
/// The number of ICMP messages which this entity did not send due to
/// problems discovered within ICMP such as a lack of buffers. This value
/// should not include errors discovered outside the ICMP layer such as the
/// inability of IP to route the resultant datagram. In some
/// implementations there may be no types of error which contribute to this
/// counter's value.
pub icmp_out_errors: u64,
/// The number of ICMP Destination Unreachable messages sent.
pub icmp_out_dest_unreachs: u64,
/// The number of ICMP Time Exceeded messages sent.
pub icmp_out_time_excds: u64,
/// The number of ICMP Parameter Problem messages sent.
pub icmp_out_parm_probs: u64,
/// The number of ICMP Source Quench messages sent.
pub icmp_out_src_quenchs: u64,
/// The number of ICMP Redirect messages sent. For a host, this object will
/// always be zero, since hosts do not send redirects.
pub icmp_out_redirects: u64,
/// The number of ICMP Echo (request) messages sent.
pub icmp_out_echos: u64,
/// The number of ICMP Echo Reply messages sent.
pub icmp_out_echo_reps: u64,
/// The number of ICMP Timestamp (request) messages sent.
pub icmp_out_timestamps: u64,
/// The number of ICMP Timestamp Reply messages sent.
pub icmp_out_timestamp_reps: u64,
/// The number of ICMP Address Mask Request messages sent.
pub icmp_out_addr_masks: u64,
/// The number of ICMP Address Mask Reply messages sent.
pub icmp_out_addr_mask_reps: u64,
// ignore ICMP numeric types
pub tcp_rto_algorithm: TcpRtoAlgorithm,
/// The minimum value permitted by a TCP implementation for the
/// retransmission timeout, measured in milliseconds. More refined
/// semantics for objects of this type depend upon the algorithm used to
/// determine the retransmission timeout. In particular, when the timeout
/// algorithm is rsre(3), an object of this type has the semantics of the
/// LBOUND quantity described in [RFC 793](https://datatracker.ietf.org/doc/html/rfc793).
pub tcp_rto_min: u64,
/// The maximum value permitted by a TCP implementation for the
/// retransmission timeout, measured in milliseconds. More refined
/// semantics for objects of this type depend upon the algorithm used to
/// determine the retransmission timeout. In particular, when the timeout
/// algorithm is rsre(3), an object of this type has the semantics of the
/// UBOUND quantity described in [RFC 793](https://datatracker.ietf.org/doc/html/rfc793).
pub tcp_rto_max: u64,
/// The limit on the total number of TCP connections the entity can support.
/// In entities where the maximum number of connections is dynamic, this
/// object should contain the value -1.
pub tcp_max_conn: i64,
/// The number of times TCP connections have made a direct transition to the
/// SYN-SENT state from the CLOSED state.
pub tcp_active_opens: u64,
/// The number of times TCP connections have made a direct transition to the
/// SYN-RCVD state from the LISTEN state.
pub tcp_passive_opens: u64,
/// The number of times TCP connections have made a direct transition to the
/// CLOSED state from either the SYN-SENT state or the SYN-RCVD state, plus
/// the number of times TCP connections have made a direct transition to the
/// LISTEN state from the SYN-RCVD state.
pub tcp_attempt_fails: u64,
/// The number of times TCP connections have made a direct transition to the
/// CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state.
pub tcp_estab_resets: u64,
/// The number of TCP connections for which the current state is either
/// ESTABLISHED or CLOSE-WAIT.
pub tcp_curr_estab: u64,
/// The total number of segments received, including those received in
/// error. This count includes segments received on currently established
/// connections.
pub tcp_in_segs: u64,
/// The total number of segments sent, including those on current
/// connections but excluding those containing only retransmitted octets.
pub tcp_out_segs: u64,
/// The total number of segments retransmitted - that is, the number of TCP
/// segments transmitted containing one or more previously transmitted octets.
pub tcp_retrans_segs: u64,
/// The total number of segments received in error (e.g., bad TCP checksums).
pub tcp_in_errs: u64,
/// The number of TCP segments sent containing the RST flag.
pub tcp_out_rsts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub tcp_in_csum_errors: u64,
/// The total number of UDP datagrams delivered to UDP users.
pub udp_in_datagrams: u64,
/// The total number of received UDP datagrams for which there was no
/// application at the destination port.
pub udp_no_ports: u64,
/// The number of received UDP datagrams that could not be delivered for
/// reasons other than the lack of an application at the destination port.
pub udp_in_errors: u64,
/// The total number of UDP datagrams sent from this entity.
pub udp_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_in_csum_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_ignored_multi: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_no_ports: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_csum_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_ignored_multi: u64,
}
/// A /proc/net/snmp section
///
/// A section represents two lines, 1x header and 1x data
/// Each line has a prefix [ip, icmp, icmpmsg, tcp, udp, udplite]
/// Eg.
/// Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
/// Tcp: 1 200 120000 -1 177 14 0 6 4 11155 10083 18 0 94 0
#[derive(Debug)]
struct SnmpSection {
prefix: String,
values: HashMap<String, String>,
}
impl<'a> SnmpSection {
fn new(hdr: String, data: String) -> ProcResult<Self> {
let mut hdr = hdr.trim_end().split_whitespace();
let mut data = data.trim_end().split_whitespace();
let prefix = expect!(hdr.next()).to_owned();
expect!(data.next());
let mut values = HashMap::new();
for hdr in hdr {
values.insert(hdr.to_owned(), expect!(data.next()).to_owned());
}
Ok(Self { prefix, values })
}
}
/// An iterator over the /proc/net/snmp sections using `BufRead`.
#[derive(Debug)]
struct SnmpSections<B> {
buf: B,
}
impl<B: BufRead> Iterator for SnmpSections<B> {
type Item = ProcResult<SnmpSection>;
fn next(&mut self) -> Option<Self::Item> {
let mut hdr = String::new();
match self.buf.read_line(&mut hdr) {
Ok(0) => None,
Ok(_n) => {
let mut data = String::new();
match self.buf.read_line(&mut data) {
Ok(_n) => Some(SnmpSection::new(hdr, data)),
Err(e) => Some(Err(e.into())),
}
}
Err(e) => Some(Err(e.into())),
}
}
}
impl super::FromBufRead for Snmp {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut map = HashMap::new();
let sections = SnmpSections { buf: r };
for section in sections.flatten() {
let p = §ion.prefix;
for (hdr, v) in §ion.values {
map.insert(format!("{p}{hdr}"), v.to_owned());
}
}
let snmp = Snmp {
// Ip
ip_forwarding: expect!(IpForwarding::from_u8(from_str!(
u8,
&expect!(map.remove("Ip:Forwarding"))
))),
ip_default_ttl: from_str!(u32, &expect!(map.remove("Ip:DefaultTTL"))),
ip_in_receives: from_str!(u64, &expect!(map.remove("Ip:InReceives"))),
ip_in_hdr_errors: from_str!(u64, &expect!(map.remove("Ip:InHdrErrors"))),
ip_in_addr_errors: from_str!(u64, &expect!(map.remove("Ip:InAddrErrors"))),
ip_forw_datagrams: from_str!(u64, &expect!(map.remove("Ip:ForwDatagrams"))),
ip_in_unknown_protos: from_str!(u64, &expect!(map.remove("Ip:InUnknownProtos"))),
ip_in_discards: from_str!(u64, &expect!(map.remove("Ip:InDiscards"))),
ip_in_delivers: from_str!(u64, &expect!(map.remove("Ip:InDelivers"))),
ip_out_requests: from_str!(u64, &expect!(map.remove("Ip:OutRequests"))),
ip_out_discards: from_str!(u64, &expect!(map.remove("Ip:OutDiscards"))),
ip_out_no_routes: from_str!(u64, &expect!(map.remove("Ip:OutNoRoutes"))),
ip_reasm_timeout: from_str!(u64, &expect!(map.remove("Ip:ReasmTimeout"))),
ip_reasm_reqds: from_str!(u64, &expect!(map.remove("Ip:ReasmReqds"))),
ip_reasm_oks: from_str!(u64, &expect!(map.remove("Ip:ReasmOKs"))),
ip_reasm_fails: from_str!(u64, &expect!(map.remove("Ip:ReasmFails"))),
ip_frag_oks: from_str!(u64, &expect!(map.remove("Ip:FragOKs"))),
ip_frag_fails: from_str!(u64, &expect!(map.remove("Ip:FragFails"))),
ip_frag_creates: from_str!(u64, &expect!(map.remove("Ip:FragCreates"))),
//ip_out_transmits: from_str!(u64, &expect!(map.remove("Ip:OutTransmits"))),
// Icmp
icmp_in_msgs: from_str!(u64, &expect!(map.remove("Icmp:InMsgs"))),
icmp_in_errors: from_str!(u64, &expect!(map.remove("Icmp:InErrors"))),
icmp_in_csum_errors: from_str!(u64, &expect!(map.remove("Icmp:InCsumErrors"))),
icmp_in_dest_unreachs: from_str!(u64, &expect!(map.remove("Icmp:InDestUnreachs"))),
icmp_in_time_excds: from_str!(u64, &expect!(map.remove("Icmp:InTimeExcds"))),
icmp_in_parm_probs: from_str!(u64, &expect!(map.remove("Icmp:InParmProbs"))),
icmp_in_src_quenchs: from_str!(u64, &expect!(map.remove("Icmp:InSrcQuenchs"))),
icmp_in_redirects: from_str!(u64, &expect!(map.remove("Icmp:InRedirects"))),
icmp_in_echos: from_str!(u64, &expect!(map.remove("Icmp:InEchos"))),
icmp_in_echo_reps: from_str!(u64, &expect!(map.remove("Icmp:InEchoReps"))),
icmp_in_timestamps: from_str!(u64, &expect!(map.remove("Icmp:InTimestamps"))),
icmp_in_timestamp_reps: from_str!(u64, &expect!(map.remove("Icmp:InTimestampReps"))),
icmp_in_addr_masks: from_str!(u64, &expect!(map.remove("Icmp:InAddrMasks"))),
icmp_in_addr_mask_reps: from_str!(u64, &expect!(map.remove("Icmp:InAddrMaskReps"))),
icmp_out_msgs: from_str!(u64, &expect!(map.remove("Icmp:OutMsgs"))),
icmp_out_errors: from_str!(u64, &expect!(map.remove("Icmp:OutErrors"))),
//icmp_out_rate_limit_global: from_str!(u64, &expect!(map.remove("Icmp:OutRateLimitGlobal"))),
//icmp_out_rate_limit_host: from_str!(u64, &expect!(map.remove("Icmp:OutRateLimitHost"))),
icmp_out_dest_unreachs: from_str!(u64, &expect!(map.remove("Icmp:OutDestUnreachs"))),
icmp_out_time_excds: from_str!(u64, &expect!(map.remove("Icmp:OutTimeExcds"))),
icmp_out_parm_probs: from_str!(u64, &expect!(map.remove("Icmp:OutParmProbs"))),
icmp_out_src_quenchs: from_str!(u64, &expect!(map.remove("Icmp:OutSrcQuenchs"))),
icmp_out_redirects: from_str!(u64, &expect!(map.remove("Icmp:OutRedirects"))),
icmp_out_echos: from_str!(u64, &expect!(map.remove("Icmp:OutEchos"))),
icmp_out_echo_reps: from_str!(u64, &expect!(map.remove("Icmp:OutEchoReps"))),
icmp_out_timestamps: from_str!(u64, &expect!(map.remove("Icmp:OutTimestamps"))),
icmp_out_timestamp_reps: from_str!(u64, &expect!(map.remove("Icmp:OutTimestampReps"))),
icmp_out_addr_masks: from_str!(u64, &expect!(map.remove("Icmp:OutAddrMasks"))),
icmp_out_addr_mask_reps: from_str!(u64, &expect!(map.remove("Icmp:OutAddrMaskReps"))),
// Tcp
tcp_rto_algorithm: expect!(TcpRtoAlgorithm::from_u8(from_str!(
u8,
&expect!(map.remove("Tcp:RtoAlgorithm"))
))),
tcp_rto_min: from_str!(u64, &expect!(map.remove("Tcp:RtoMin"))),
tcp_rto_max: from_str!(u64, &expect!(map.remove("Tcp:RtoMax"))),
tcp_max_conn: from_str!(i64, &expect!(map.remove("Tcp:MaxConn"))),
tcp_active_opens: from_str!(u64, &expect!(map.remove("Tcp:ActiveOpens"))),
tcp_passive_opens: from_str!(u64, &expect!(map.remove("Tcp:PassiveOpens"))),
tcp_attempt_fails: from_str!(u64, &expect!(map.remove("Tcp:AttemptFails"))),
tcp_estab_resets: from_str!(u64, &expect!(map.remove("Tcp:EstabResets"))),
tcp_curr_estab: from_str!(u64, &expect!(map.remove("Tcp:CurrEstab"))),
tcp_in_segs: from_str!(u64, &expect!(map.remove("Tcp:InSegs"))),
tcp_out_segs: from_str!(u64, &expect!(map.remove("Tcp:OutSegs"))),
tcp_retrans_segs: from_str!(u64, &expect!(map.remove("Tcp:RetransSegs"))),
tcp_in_errs: from_str!(u64, &expect!(map.remove("Tcp:InErrs"))),
tcp_out_rsts: from_str!(u64, &expect!(map.remove("Tcp:OutRsts"))),
tcp_in_csum_errors: from_str!(u64, &expect!(map.remove("Tcp:InCsumErrors"))),
// Udp
udp_in_datagrams: from_str!(u64, &expect!(map.remove("Udp:InDatagrams"))),
udp_no_ports: from_str!(u64, &expect!(map.remove("Udp:NoPorts"))),
udp_in_errors: from_str!(u64, &expect!(map.remove("Udp:InErrors"))),
udp_out_datagrams: from_str!(u64, &expect!(map.remove("Udp:OutDatagrams"))),
udp_rcvbuf_errors: from_str!(u64, &expect!(map.remove("Udp:RcvbufErrors"))),
udp_sndbuf_errors: from_str!(u64, &expect!(map.remove("Udp:SndbufErrors"))),
udp_in_csum_errors: from_str!(u64, &expect!(map.remove("Udp:InCsumErrors"))),
udp_ignored_multi: from_str!(u64, &expect!(map.remove("Udp:IgnoredMulti"))),
//udp_mem_errors: from_str!(u64, &expect!(map.remove("Udp:MemErrors"))),
// UdpLite
udp_lite_in_datagrams: from_str!(u64, &expect!(map.remove("UdpLite:InDatagrams"))),
udp_lite_no_ports: from_str!(u64, &expect!(map.remove("UdpLite:NoPorts"))),
udp_lite_in_errors: from_str!(u64, &expect!(map.remove("UdpLite:InErrors"))),
udp_lite_out_datagrams: from_str!(u64, &expect!(map.remove("UdpLite:OutDatagrams"))),
udp_lite_rcvbuf_errors: from_str!(u64, &expect!(map.remove("UdpLite:RcvbufErrors"))),
udp_lite_sndbuf_errors: from_str!(u64, &expect!(map.remove("UdpLite:SndbufErrors"))),
udp_lite_in_csum_errors: from_str!(u64, &expect!(map.remove("UdpLite:InCsumErrors"))),
udp_lite_ignored_multi: from_str!(u64, &expect!(map.remove("UdpLite:IgnoredMulti"))),
//udp_lite_mem_errors: from_str!(u64, &expect!(map.remove("UdpLite:MemErrors"))),
};
Ok(snmp)
}
}
/// This struct holds the data needed for the IP, ICMP, TCP, and UDP management
/// information bases for an SNMP agent.
///
/// Note that this struct is only for IPv6
///
/// For more details, see [RFC1213](https://datatracker.ietf.org/doc/html/rfc1213)
/// and [SNMP counter](https://docs.kernel.org/networking/snmp_counter.html)
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Snmp6 {
/// The total number of input datagrams received from interfaces, including
/// those received in error.
pub ip_in_receives: u64,
/// The number of input datagrams discarded due to errors in their IP
/// headers.
pub ip_in_hdr_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_too_big_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_no_routes: u64,
/// The number of input datagrams discarded because the IP address in their
/// IP header's destination field was not a valid address to be received at
/// this entity.
pub ip_in_addr_errors: u64,
/// The number of locally-addressed datagrams received successfully but
/// discarded because of an unknown or unsupported protocol.
pub ip_in_unknown_protos: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_truncated_pkts: u64,
/// The number of input IP datagrams for which no problems were encountered
/// to prevent their continued processing, but which were discarded
/// (e.g., for lack of buffer space).
pub ip_in_discards: u64,
/// The total number of input datagrams successfully delivered to IP
/// user-protocols (including ICMP).
///
/// Note that this counter does not include any datagrams discarded while
/// awaiting re-assembly.
pub ip_in_delivers: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_forw_datagrams: u64,
/// The total number of IP datagrams which local IP user-protocols
/// (including ICMP) supplied to IP in requests for transmission.
///
/// Note that this counter does not include any datagrams counted in
/// ipForwDatagrams.
pub ip_out_requests: u64,
/// The number of output IP datagrams for which no problem was encountered
/// to prevent their transmission to their destination, but which were
/// discarded (e.g., for lack of buffer space).
///
/// Note that this counter would include datagrams counted in
/// `IpForwDatagrams` if any such packets met this (discretionary) discard
/// criterion.
pub ip_out_discards: u64,
/// The number of IP datagrams discarded because no route could be found to
/// transmit them to their destination.
///
/// Note that this counter includes any packets counted in `IpForwDatagrams`
/// which meet this `no-route' criterion.
///
/// Note that this includes any datagarms which a host cannot route because
/// all of its default gateways are down.
pub ip_out_no_routes: u64,
/// The maximum number of seconds which received fragments are held while
/// they are awaiting reassembly at this entity.
pub ip_reasm_timeout: u64,
/// The number of IP fragments received which needed to be reassembled at
/// this entity.
pub ip_reasm_reqds: u64,
/// The number of IP datagrams successfully re-assembled.
pub ip_reasm_oks: u64,
/// The number of failures detected by the IP re-assembly algorithm
/// (for whatever reason: timed out, errors, etc).
///
/// Note that this is not necessarily a count of discarded IP fragments
/// since some algorithms (notably the algorithm in [RFC 815](https://datatracker.ietf.org/doc/html/rfc815))
/// can lose track of the number of fragments by combining them as they are
/// received.
pub ip_reasm_fails: u64,
/// The number of IP datagrams that have been successfully fragmented at
/// this entity.
pub ip_frag_oks: u64,
/// The number of IP datagrams that have been discarded because they needed
/// to be fragmented at this entity but could not be, e.g., because their
/// `Don't Fragment` flag was set.
pub ip_frag_fails: u64,
/// The number of IP datagram fragments that have been generated as a result
/// of fragmentation at this entity.
pub ip_frag_creates: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_mcast_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_mcast_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_mcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_mcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_bcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_bcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_no_ect_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_ect1_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_ect0_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_ce_pkts: u64,
/// The total number of ICMP messages which the entity received.
///
/// Note that this counter includes all those counted by `icmp_in_errors`.
pub icmp_in_msgs: u64,
/// The number of ICMP messages which the entity received but determined as
/// having ICMP-specific errors (bad ICMP checksums, bad length, etc.
pub icmp_in_errors: u64,
/// The total number of ICMP messages which this entity attempted to send.
///
/// Note that this counter includes all those counted by `icmp_out_errors`.
pub icmp_out_msgs: u64,
/// The number of ICMP messages which this entity did not send due to
/// problems discovered within ICMP such as a lack of buffers. This value
/// should not include errors discovered outside the ICMP layer such as the
/// inability of IP to route the resultant datagram. In some
/// implementations there may be no types of error which contribute to this
/// counter's value.
pub icmp_out_errors: u64,
/// This counter indicates the checksum of the ICMP packet is wrong.
///
/// Non RFC1213 field
pub icmp_in_csum_errors: u64,
/// The number of ICMP Destination Unreachable messages received.
pub icmp_in_dest_unreachs: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_pkt_too_bigs: u64,
/// The number of ICMP Time Exceeded messages received.
pub icmp_in_time_excds: u64,
/// The number of ICMP Parameter Problem messages received.
pub icmp_in_parm_problem: u64,
/// The number of ICMP Echo (request) messages received.
pub icmp_in_echos: u64,
/// The number of ICMP Echo Reply messages received.
pub icmp_in_echo_replies: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_group_memb_queries: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_group_memb_responses: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_group_memb_reductions: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_router_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_router_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_neighbor_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_neighbor_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_redirects: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_mldv2_reports: u64,
/// The number of ICMP Destination Unreachable messages sent.
pub icmp_out_dest_unreachs: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_pkt_too_bigs: u64,
/// The number of ICMP Time Exceeded messages sent.
pub icmp_out_time_excds: u64,
/// The number of ICMP Parameter Problem messages sent.
pub icmp_out_parm_problems: u64,
/// The number of ICMP Echo (request) messages sent.
pub icmp_out_echos: u64,
/// The number of ICMP Echo Reply messages sent.
pub icmp_out_echo_replies: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_group_memb_queries: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_group_memb_responses: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_group_memb_reductions: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_router_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_router_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_neighbor_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_neighbor_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_redirects: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_mldv2_reports: u64,
//
// ignore ICMP numeric types
//
/// The total number of UDP datagrams delivered to UDP users.
pub udp_in_datagrams: u64,
/// The total number of received UDP datagrams for which there was no
/// application at the destination port.
pub udp_no_ports: u64,
/// The number of received UDP datagrams that could not be delivered for
/// reasons other than the lack of an application at the destination port.
pub udp_in_errors: u64,
/// The total number of UDP datagrams sent from this entity.
pub udp_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_in_csum_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_ignored_multi: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_no_ports: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_csum_errors: u64,
}
impl super::FromBufRead for Snmp6 {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut map = HashMap::new();
for line in r.lines() {
let line = expect!(line);
if line.is_empty() {
continue;
}
let mut s = line.split_whitespace();
let field = expect!(s.next(), "no field");
if field.starts_with("Icmp6InType") || field.starts_with("Icmp6OutType") {
continue;
}
let value = from_str!(u64, expect!(s.next(), "no value"));
map.insert(field.to_string(), value);
}
let snmp6 = Snmp6 {
ip_in_receives: expect!(map.remove("Ip6InReceives")),
ip_in_hdr_errors: expect!(map.remove("Ip6InHdrErrors")),
ip_in_too_big_errors: expect!(map.remove("Ip6InTooBigErrors")),
ip_in_no_routes: expect!(map.remove("Ip6InNoRoutes")),
ip_in_addr_errors: expect!(map.remove("Ip6InAddrErrors")),
ip_in_unknown_protos: expect!(map.remove("Ip6InUnknownProtos")),
ip_in_truncated_pkts: expect!(map.remove("Ip6InTruncatedPkts")),
ip_in_discards: expect!(map.remove("Ip6InDiscards")),
ip_in_delivers: expect!(map.remove("Ip6InDelivers")),
ip_out_forw_datagrams: expect!(map.remove("Ip6OutForwDatagrams")),
ip_out_requests: expect!(map.remove("Ip6OutRequests")),
ip_out_discards: expect!(map.remove("Ip6OutDiscards")),
ip_out_no_routes: expect!(map.remove("Ip6OutNoRoutes")),
ip_reasm_timeout: expect!(map.remove("Ip6ReasmTimeout")),
ip_reasm_reqds: expect!(map.remove("Ip6ReasmReqds")),
ip_reasm_oks: expect!(map.remove("Ip6ReasmOKs")),
ip_reasm_fails: expect!(map.remove("Ip6ReasmFails")),
ip_frag_oks: expect!(map.remove("Ip6FragOKs")),
ip_frag_fails: expect!(map.remove("Ip6FragFails")),
ip_frag_creates: expect!(map.remove("Ip6FragCreates")),
ip_in_mcast_pkts: expect!(map.remove("Ip6InMcastPkts")),
ip_out_mcast_pkts: expect!(map.remove("Ip6OutMcastPkts")),
ip_in_octets: expect!(map.remove("Ip6InOctets")),
ip_out_octets: expect!(map.remove("Ip6OutOctets")),
ip_in_mcast_octets: expect!(map.remove("Ip6InMcastOctets")),
ip_out_mcast_octets: expect!(map.remove("Ip6OutMcastOctets")),
ip_in_bcast_octets: expect!(map.remove("Ip6InBcastOctets")),
ip_out_bcast_octets: expect!(map.remove("Ip6OutBcastOctets")),
ip_in_no_ect_pkts: expect!(map.remove("Ip6InNoECTPkts")),
ip_in_ect1_pkts: expect!(map.remove("Ip6InECT1Pkts")),
ip_in_ect0_pkts: expect!(map.remove("Ip6InECT0Pkts")),
ip_in_ce_pkts: expect!(map.remove("Ip6InCEPkts")),
icmp_in_msgs: expect!(map.remove("Icmp6InMsgs")),
icmp_in_errors: expect!(map.remove("Icmp6InErrors")),
icmp_out_msgs: expect!(map.remove("Icmp6OutMsgs")),
icmp_out_errors: expect!(map.remove("Icmp6OutErrors")),
icmp_in_csum_errors: expect!(map.remove("Icmp6InCsumErrors")),
icmp_in_dest_unreachs: expect!(map.remove("Icmp6InDestUnreachs")),
icmp_in_pkt_too_bigs: expect!(map.remove("Icmp6InPktTooBigs")),
icmp_in_time_excds: expect!(map.remove("Icmp6InTimeExcds")),
icmp_in_parm_problem: expect!(map.remove("Icmp6InParmProblems")),
icmp_in_echos: expect!(map.remove("Icmp6InEchos")),
icmp_in_echo_replies: expect!(map.remove("Icmp6InEchoReplies")),
icmp_in_group_memb_queries: expect!(map.remove("Icmp6InGroupMembQueries")),
icmp_in_group_memb_responses: expect!(map.remove("Icmp6InGroupMembResponses")),
icmp_in_group_memb_reductions: expect!(map.remove("Icmp6InGroupMembReductions")),
icmp_in_router_solicits: expect!(map.remove("Icmp6InRouterSolicits")),
icmp_in_router_advertisements: expect!(map.remove("Icmp6InRouterAdvertisements")),
icmp_in_neighbor_solicits: expect!(map.remove("Icmp6InNeighborSolicits")),
icmp_in_neighbor_advertisements: expect!(map.remove("Icmp6InNeighborAdvertisements")),
icmp_in_redirects: expect!(map.remove("Icmp6InRedirects")),
icmp_in_mldv2_reports: expect!(map.remove("Icmp6InMLDv2Reports")),
icmp_out_dest_unreachs: expect!(map.remove("Icmp6OutDestUnreachs")),
icmp_out_pkt_too_bigs: expect!(map.remove("Icmp6OutPktTooBigs")),
icmp_out_time_excds: expect!(map.remove("Icmp6OutTimeExcds")),
icmp_out_parm_problems: expect!(map.remove("Icmp6OutParmProblems")),
icmp_out_echos: expect!(map.remove("Icmp6OutEchos")),
icmp_out_echo_replies: expect!(map.remove("Icmp6OutEchoReplies")),
icmp_out_group_memb_queries: expect!(map.remove("Icmp6OutGroupMembQueries")),
icmp_out_group_memb_responses: expect!(map.remove("Icmp6OutGroupMembResponses")),
icmp_out_group_memb_reductions: expect!(map.remove("Icmp6OutGroupMembReductions")),
icmp_out_router_solicits: expect!(map.remove("Icmp6OutRouterSolicits")),
icmp_out_router_advertisements: expect!(map.remove("Icmp6OutRouterAdvertisements")),
icmp_out_neighbor_solicits: expect!(map.remove("Icmp6OutNeighborSolicits")),
icmp_out_neighbor_advertisements: expect!(map.remove("Icmp6OutNeighborAdvertisements")),
icmp_out_redirects: expect!(map.remove("Icmp6OutRedirects")),
icmp_out_mldv2_reports: expect!(map.remove("Icmp6OutMLDv2Reports")),
//
// ignore ICMP numeric types
//
udp_in_datagrams: expect!(map.remove("Udp6InDatagrams")),
udp_no_ports: expect!(map.remove("Udp6NoPorts")),
udp_in_errors: expect!(map.remove("Udp6InErrors")),
udp_out_datagrams: expect!(map.remove("Udp6OutDatagrams")),
udp_rcvbuf_errors: expect!(map.remove("Udp6RcvbufErrors")),
udp_sndbuf_errors: expect!(map.remove("Udp6SndbufErrors")),
udp_in_csum_errors: expect!(map.remove("Udp6InCsumErrors")),
udp_ignored_multi: expect!(map.remove("Udp6IgnoredMulti")),
udp_lite_in_datagrams: expect!(map.remove("UdpLite6InDatagrams")),
udp_lite_no_ports: expect!(map.remove("UdpLite6NoPorts")),
udp_lite_in_errors: expect!(map.remove("UdpLite6InErrors")),
udp_lite_out_datagrams: expect!(map.remove("UdpLite6OutDatagrams")),
udp_lite_rcvbuf_errors: expect!(map.remove("UdpLite6RcvbufErrors")),
udp_lite_sndbuf_errors: expect!(map.remove("UdpLite6SndbufErrors")),
udp_lite_in_csum_errors: expect!(map.remove("UdpLite6InCsumErrors")),
};
if cfg!(test) {
assert!(map.is_empty(), "snmp6 map is not empty: {:#?}", map);
}
Ok(snmp6)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::IpAddr;
#[test]
fn test_parse_ipaddr() {
use std::str::FromStr;
let addr = parse_addressport_str("0100007F:1234", true).unwrap();
assert_eq!(addr.port(), 0x1234);
match addr.ip() {
IpAddr::V4(addr) => assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)),
_ => panic!("Not IPv4"),
}
// When you connect to [2a00:1450:4001:814::200e]:80 (ipv6.google.com) the entry with
// 5014002A14080140000000000E200000:0050 remote endpoint is created in /proc/net/tcp6
// on Linux 4.19.
let addr = parse_addressport_str("5014002A14080140000000000E200000:0050", true).unwrap();
assert_eq!(addr.port(), 80);
match addr.ip() {
IpAddr::V6(addr) => assert_eq!(addr, Ipv6Addr::from_str("2a00:1450:4001:814::200e").unwrap()),
_ => panic!("Not IPv6"),
}
// IPv6 test case from https://stackoverflow.com/questions/41940483/parse-ipv6-addresses-from-proc-net-tcp6-python-2-7/41948004#41948004
let addr = parse_addressport_str("B80D01200000000067452301EFCDAB89:0", true).unwrap();
assert_eq!(addr.port(), 0);
match addr.ip() {
IpAddr::V6(addr) => assert_eq!(addr, Ipv6Addr::from_str("2001:db8::123:4567:89ab:cdef").unwrap()),
_ => panic!("Not IPv6"),
}
let addr = parse_addressport_str("1234:1234", true);
assert!(addr.is_err());
}
#[test]
fn test_tcpstate_from() {
assert_eq!(TcpState::from_u8(0xA).unwrap(), TcpState::Listen);
}
#[test]
fn test_snmp_debian_6_8_12() {
// Sample from Debian 6.8.12-1
let data = r#"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates OutTransmits
Ip: 1 64 58881328 0 1 0 0 0 58879082 12449667 9745 1855 0 4 2 0 0 0 0 12449667
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutRateLimitGlobal OutRateLimitHost OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 16667 83 0 16667 0 0 0 0 0 0 0 0 0 0 21854 0 2 81 21854 0 0 0 0 0 0 0 0 0 0
IcmpMsg: InType3 OutType3
IcmpMsg: 16667 21854
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
Tcp: 1 200 120000 -1 88170 33742 29003 4952 9 5129401 4676076 3246 60 40857 0
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors
Udp: 48327329 21522 6981741 9605045 6981727 9497 14 478236 0
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors
UdpLite: 0 0 0 0 0 0 0 0 0
"#;
let r = std::io::Cursor::new(data.as_bytes());
use crate::FromRead;
let res = Snmp::from_read(r).unwrap();
assert_eq!(res.ip_forwarding, IpForwarding::Forwarding);
assert_eq!(res.ip_in_receives, 58881328);
assert_eq!(res.ip_in_delivers, 58879082);
assert_eq!(res.ip_out_requests, 12449667);
assert_eq!(res.ip_out_no_routes, 1855);
assert_eq!(res.tcp_rto_algorithm, TcpRtoAlgorithm::Other);
assert_eq!(res.tcp_rto_min, 200);
assert_eq!(res.tcp_rto_max, 120000);
assert_eq!(res.tcp_max_conn, -1);
assert_eq!(res.tcp_curr_estab, 9);
assert_eq!(res.tcp_in_segs, 5129401);
assert_eq!(res.tcp_out_segs, 4676076);
assert_eq!(res.udp_in_datagrams, 48327329);
assert_eq!(res.udp_in_csum_errors, 14);
assert_eq!(res.udp_no_ports, 21522);
assert_eq!(res.udp_out_datagrams, 9605045);
println!("{res:?}");
}
#[test]
fn test_snmp_missing_icmp_msg() {
// https://github.com/eminence/procfs/issues/310
let data = r#"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates OutTransmits
Ip: 2 64 12063 0 1 0 0 0 11952 8953 0 0 0 0 0 0 0 0 0 8953
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutRateLimitGlobal OutRateLimitHost OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
Tcp: 1 200 120000 -1 177 14 0 6 4 11155 10083 18 0 94 0
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors
Udp: 2772 0 0 1890 0 0 0 745 0
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors
UdpLite: 0 0 0 0 0 0 0 0 0
"#;
let r = std::io::Cursor::new(data.as_bytes());
use crate::FromRead;
let res = Snmp::from_read(r).unwrap();
println!("{res:?}");
}
}