1use crate::error::FourWordError;
7use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
8
9const MAX_BITS: usize = 42;
11
12#[repr(u8)]
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum AddressType {
16 Ipv4Localhost = 0b000, Ipv4Private192 = 0b001, Ipv4Private10 = 0b010, Ipv4Private172 = 0b011, Ipv4Public = 0b100, Ipv6Localhost = 0b1100, Ipv6LinkLocal = 0b1101, Ipv6UniqueLocal = 0b1110, Ipv6Public = 0b1111, }
28
29#[derive(Debug, Clone)]
31pub struct PortCompressor {
32 common_ports: Vec<(u16, u8)>,
34 frequent_ports: Vec<(u16, u8)>,
36}
37
38impl Default for PortCompressor {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl PortCompressor {
45 pub fn new() -> Self {
46 Self {
47 common_ports: vec![
49 (80, 0x0), (443, 0x1), (22, 0x2), (21, 0x3), (25, 0x4), (53, 0x5), (8080, 0x6), (3306, 0x7), (5432, 0x8), (6379, 0x9), (27017, 0xA), (8443, 0xB), (3000, 0xC), (5000, 0xD), (8000, 0xE), (9000, 0xF), ],
66 frequent_ports: vec![
68 (23, 0x10), (110, 0x11), (143, 0x12), (445, 0x13), (1433, 0x14), (1521, 0x15), (2049, 0x16), (3389, 0x17), (5900, 0x18), (8081, 0x19), (8082, 0x1A), (8083, 0x1B), (8888, 0x1C), (9090, 0x1D), (9200, 0x1E), (11211, 0x1F), ],
86 }
87 }
88
89 pub fn compress(&self, port: Option<u16>) -> (Vec<u8>, usize) {
90 match port {
91 None => (vec![], 0), Some(p) => {
93 if let Some((_, code)) = self.common_ports.iter().find(|(port, _)| *port == p) {
95 (vec![*code], 4)
96 }
97 else if let Some((_, code)) =
99 self.frequent_ports.iter().find(|(port, _)| *port == p)
100 {
101 (vec![*code], 8)
102 }
103 else {
105 (vec![(p >> 8) as u8, (p & 0xFF) as u8], 16)
106 }
107 }
108 }
109 }
110
111 pub fn decompress(&self, data: &[u8], bits: usize) -> Result<Option<u16>, FourWordError> {
112 match bits {
113 0 => Ok(None),
114 4 => {
115 let code = data[0] & 0x0F;
116 self.common_ports
117 .iter()
118 .find(|(_, c)| *c == code)
119 .map(|(port, _)| Some(*port))
120 .ok_or_else(|| {
121 FourWordError::InvalidInput("Invalid common port code".to_string())
122 })
123 }
124 8 => {
125 let code = data[0];
126 if code <= 0x0F {
128 self.common_ports
129 .iter()
130 .find(|(_, c)| *c == code)
131 .map(|(port, _)| Some(*port))
132 .ok_or_else(|| FourWordError::InvalidInput("Invalid port code".to_string()))
133 } else {
134 self.frequent_ports
135 .iter()
136 .find(|(_, c)| *c == code)
137 .map(|(port, _)| Some(*port))
138 .ok_or_else(|| {
139 FourWordError::InvalidInput("Invalid frequent port code".to_string())
140 })
141 }
142 }
143 16 => {
144 if data.len() >= 2 {
145 Ok(Some(((data[0] as u16) << 8) | (data[1] as u16)))
146 } else {
147 Err(FourWordError::InvalidInput(
148 "Insufficient data for port".to_string(),
149 ))
150 }
151 }
152 _ => Err(FourWordError::InvalidInput(format!(
153 "Invalid port bit count: {bits}"
154 ))),
155 }
156 }
157}
158
159pub struct IpCompressor {
161 port_compressor: PortCompressor,
162}
163
164impl Default for IpCompressor {
165 fn default() -> Self {
166 Self::new()
167 }
168}
169
170impl IpCompressor {
171 pub fn new() -> Self {
172 Self {
173 port_compressor: PortCompressor::new(),
174 }
175 }
176
177 pub fn compress(
179 &self,
180 ip: &IpAddr,
181 port: Option<u16>,
182 ) -> Result<CompressedAddress, FourWordError> {
183 let (addr_type, addr_data, addr_bits) = self.compress_address(ip)?;
184 let (port_data, port_bits) = self.port_compressor.compress(port);
185
186 let total_bits = addr_bits + port_bits;
187 if total_bits > MAX_BITS {
188 return Err(FourWordError::InvalidInput(format!(
189 "Compressed size {total_bits} bits exceeds maximum {MAX_BITS} bits"
190 )));
191 }
192
193 Ok(CompressedAddress {
194 addr_type,
195 addr_data,
196 addr_bits,
197 port_data,
198 port_bits,
199 total_bits,
200 })
201 }
202
203 fn compress_address(
205 &self,
206 ip: &IpAddr,
207 ) -> Result<(AddressType, Vec<u8>, usize), FourWordError> {
208 match ip {
209 IpAddr::V4(ipv4) => self.compress_ipv4(ipv4),
210 IpAddr::V6(ipv6) => self.compress_ipv6(ipv6),
211 }
212 }
213
214 fn compress_ipv4(
215 &self,
216 ipv4: &Ipv4Addr,
217 ) -> Result<(AddressType, Vec<u8>, usize), FourWordError> {
218 let octets = ipv4.octets();
219
220 if octets[0] == 127 {
222 Ok((AddressType::Ipv4Localhost, vec![octets[3]], 11))
223 }
224 else if octets[0] == 192 && octets[1] == 168 {
226 Ok((AddressType::Ipv4Private192, vec![octets[2], octets[3]], 19))
227 }
228 else if octets[0] == 10 {
230 Ok((
231 AddressType::Ipv4Private10,
232 vec![octets[1], octets[2], octets[3]],
233 27,
234 ))
235 }
236 else if octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31 {
238 let range_bits = octets[1] - 16; Ok((
240 AddressType::Ipv4Private172,
241 vec![range_bits, octets[2], octets[3]],
242 23,
243 ))
244 }
245 else {
247 Ok((AddressType::Ipv4Public, octets.to_vec(), 35))
248 }
249 }
250
251 fn compress_ipv6(
252 &self,
253 ipv6: &Ipv6Addr,
254 ) -> Result<(AddressType, Vec<u8>, usize), FourWordError> {
255 let segments = ipv6.segments();
256
257 if ipv6.is_loopback() {
259 Ok((AddressType::Ipv6Localhost, vec![], 4))
260 }
261 else if segments[0] & 0xFFC0 == 0xFE80 {
263 let interface_id = ((segments[6] as u32) << 16) | (segments[7] as u32);
267 Ok((
268 AddressType::Ipv6LinkLocal,
269 vec![
270 (interface_id >> 24) as u8,
271 (interface_id >> 16) as u8,
272 (interface_id >> 8) as u8,
273 interface_id as u8,
274 ],
275 36,
276 )) }
278 else if segments[0] & 0xFE00 == 0xFC00 {
280 Ok((
282 AddressType::Ipv6UniqueLocal,
283 vec![
284 (segments[0] >> 8) as u8,
285 segments[0] as u8,
286 (segments[1] >> 8) as u8,
287 segments[1] as u8,
288 (segments[2] >> 8) as u8,
289 segments[2] as u8,
290 ],
291 52,
292 )) }
294 else {
296 Err(FourWordError::InvalidInput(
297 "Public IPv6 addresses cannot be compressed to fit in 42 bits".to_string(),
298 ))
299 }
300 }
301
302 pub fn decompress(
304 &self,
305 compressed: &CompressedAddress,
306 ) -> Result<(IpAddr, Option<u16>), FourWordError> {
307 let ip = self.decompress_address(compressed.addr_type, &compressed.addr_data)?;
308 let port = self
309 .port_compressor
310 .decompress(&compressed.port_data, compressed.port_bits)?;
311 Ok((ip, port))
312 }
313
314 fn decompress_address(
315 &self,
316 addr_type: AddressType,
317 data: &[u8],
318 ) -> Result<IpAddr, FourWordError> {
319 match addr_type {
320 AddressType::Ipv4Localhost => {
321 if !data.is_empty() {
322 Ok(IpAddr::V4(Ipv4Addr::new(127, 0, 0, data[0])))
323 } else {
324 Ok(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)))
325 }
326 }
327 AddressType::Ipv4Private192 => {
328 if data.len() >= 2 {
329 Ok(IpAddr::V4(Ipv4Addr::new(192, 168, data[0], data[1])))
330 } else {
331 Err(FourWordError::InvalidInput(
332 "Insufficient data for 192.168.x.x".to_string(),
333 ))
334 }
335 }
336 AddressType::Ipv4Private10 => {
337 if data.len() >= 3 {
338 Ok(IpAddr::V4(Ipv4Addr::new(10, data[0], data[1], data[2])))
339 } else {
340 Err(FourWordError::InvalidInput(
341 "Insufficient data for 10.x.x.x".to_string(),
342 ))
343 }
344 }
345 AddressType::Ipv4Private172 => {
346 if data.len() >= 3 {
347 let second_octet = 16 + data[0]; Ok(IpAddr::V4(Ipv4Addr::new(
349 172,
350 second_octet,
351 data[1],
352 data[2],
353 )))
354 } else {
355 Err(FourWordError::InvalidInput(
356 "Insufficient data for 172.16-31.x.x".to_string(),
357 ))
358 }
359 }
360 AddressType::Ipv4Public => {
361 if data.len() >= 4 {
362 Ok(IpAddr::V4(Ipv4Addr::new(
363 data[0], data[1], data[2], data[3],
364 )))
365 } else {
366 Err(FourWordError::InvalidInput(
367 "Insufficient data for public IPv4".to_string(),
368 ))
369 }
370 }
371 AddressType::Ipv6Localhost => Ok(IpAddr::V6(Ipv6Addr::LOCALHOST)),
372 AddressType::Ipv6LinkLocal => {
373 if data.len() >= 4 {
374 let interface_id = ((data[0] as u32) << 24)
376 | ((data[1] as u32) << 16)
377 | ((data[2] as u32) << 8)
378 | (data[3] as u32);
379 Ok(IpAddr::V6(Ipv6Addr::new(
380 0xfe80,
381 0,
382 0,
383 0,
384 0,
385 0,
386 (interface_id >> 16) as u16,
387 (interface_id & 0xFFFF) as u16,
388 )))
389 } else {
390 Err(FourWordError::InvalidInput(
391 "Insufficient data for link-local IPv6".to_string(),
392 ))
393 }
394 }
395 AddressType::Ipv6UniqueLocal => {
396 if data.len() >= 6 {
397 let seg0 = ((data[0] as u16) << 8) | (data[1] as u16);
398 let seg1 = ((data[2] as u16) << 8) | (data[3] as u16);
399 let seg2 = ((data[4] as u16) << 8) | (data[5] as u16);
400 Ok(IpAddr::V6(Ipv6Addr::new(seg0, seg1, seg2, 0, 0, 0, 0, 0)))
401 } else {
402 Err(FourWordError::InvalidInput(
403 "Insufficient data for unique local IPv6".to_string(),
404 ))
405 }
406 }
407 AddressType::Ipv6Public => Err(FourWordError::InvalidInput(
408 "Public IPv6 decompression not supported".to_string(),
409 )),
410 }
411 }
412}
413
414#[derive(Debug, Clone)]
416pub struct CompressedAddress {
417 pub addr_type: AddressType,
418 pub addr_data: Vec<u8>,
419 pub addr_bits: usize,
420 pub port_data: Vec<u8>,
421 pub port_bits: usize,
422 pub total_bits: usize,
423}
424
425impl CompressedAddress {
426 pub fn pack(&self) -> Vec<u8> {
428 let mut bits = BitWriter::new();
429
430 match self.addr_type {
432 AddressType::Ipv4Localhost
434 | AddressType::Ipv4Private192
435 | AddressType::Ipv4Private10
436 | AddressType::Ipv4Private172
437 | AddressType::Ipv4Public => {
438 bits.write_bits(self.addr_type as u32, 3);
439 }
440 AddressType::Ipv6Localhost
442 | AddressType::Ipv6LinkLocal
443 | AddressType::Ipv6UniqueLocal
444 | AddressType::Ipv6Public => {
445 bits.write_bits(self.addr_type as u32, 4);
446 }
447 }
448
449 match self.addr_type {
451 AddressType::Ipv4Localhost => {
452 if !self.addr_data.is_empty() {
454 bits.write_bits(self.addr_data[0] as u32, 8);
455 }
456 }
457 AddressType::Ipv4Private192 => {
458 for byte in &self.addr_data {
460 bits.write_bits(*byte as u32, 8);
461 }
462 }
463 AddressType::Ipv4Private10 => {
464 for byte in &self.addr_data {
466 bits.write_bits(*byte as u32, 8);
467 }
468 }
469 AddressType::Ipv4Private172 => {
470 if self.addr_data.len() >= 3 {
472 bits.write_bits(self.addr_data[0] as u32, 4); bits.write_bits(self.addr_data[1] as u32, 8); bits.write_bits(self.addr_data[2] as u32, 8); }
476 }
477 AddressType::Ipv4Public => {
478 for byte in &self.addr_data {
480 bits.write_bits(*byte as u32, 8);
481 }
482 }
483 AddressType::Ipv6Localhost => {
484 }
486 AddressType::Ipv6LinkLocal => {
487 for byte in &self.addr_data {
489 bits.write_bits(*byte as u32, 8);
490 }
491 }
492 AddressType::Ipv6UniqueLocal => {
493 for byte in &self.addr_data {
495 bits.write_bits(*byte as u32, 8);
496 }
497 }
498 AddressType::Ipv6Public => {
499 }
501 }
502
503 if self.port_bits > 0 {
505 bits.write_bits(1, 1); if self.port_bits == 4 {
507 bits.write_bits(0, 1); bits.write_bits(self.port_data[0] as u32, 4);
509 } else if self.port_bits == 8 {
510 bits.write_bits(1, 1); bits.write_bits(0, 1); bits.write_bits(self.port_data[0] as u32, 8);
513 } else {
514 bits.write_bits(1, 1); bits.write_bits(1, 1); bits.write_bits(
517 ((self.port_data[0] as u32) << 8) | (self.port_data[1] as u32),
518 16,
519 );
520 }
521 } else {
522 bits.write_bits(0, 1); }
524
525 bits.finish()
526 }
527
528 pub fn unpack(
530 data: &[u8],
531 compressor: &IpCompressor,
532 ) -> Result<(IpAddr, Option<u16>), FourWordError> {
533 let mut bits = BitReader::new(data);
534
535 let first_3_bits = bits.read_bits(3)? as u8;
537 let (addr_type, _type_bits) = if first_3_bits < 0b110 {
538 (
540 match first_3_bits {
541 0b000 => AddressType::Ipv4Localhost,
542 0b001 => AddressType::Ipv4Private192,
543 0b010 => AddressType::Ipv4Private10,
544 0b011 => AddressType::Ipv4Private172,
545 0b100 => AddressType::Ipv4Public,
546 _ => unreachable!(),
547 },
548 3,
549 )
550 } else {
551 let fourth_bit = bits.read_bits(1)? as u8;
553 let ipv6_type = (first_3_bits << 1) | fourth_bit;
554 (
555 match ipv6_type {
556 0b1100 => AddressType::Ipv6Localhost,
557 0b1101 => AddressType::Ipv6LinkLocal,
558 0b1110 => AddressType::Ipv6UniqueLocal,
559 0b1111 => AddressType::Ipv6Public,
560 _ => unreachable!(),
561 },
562 4,
563 )
564 };
565
566 let addr_data = match addr_type {
568 AddressType::Ipv4Localhost => vec![bits.read_bits(8)? as u8],
569 AddressType::Ipv4Private192 => vec![bits.read_bits(8)? as u8, bits.read_bits(8)? as u8],
570 AddressType::Ipv4Private10 => vec![
571 bits.read_bits(8)? as u8,
572 bits.read_bits(8)? as u8,
573 bits.read_bits(8)? as u8,
574 ],
575 AddressType::Ipv4Private172 => vec![
576 bits.read_bits(4)? as u8,
577 bits.read_bits(8)? as u8,
578 bits.read_bits(8)? as u8,
579 ],
580 AddressType::Ipv4Public => vec![
581 bits.read_bits(8)? as u8,
582 bits.read_bits(8)? as u8,
583 bits.read_bits(8)? as u8,
584 bits.read_bits(8)? as u8,
585 ],
586 AddressType::Ipv6Localhost => vec![],
587 AddressType::Ipv6LinkLocal => vec![
588 bits.read_bits(8)? as u8,
589 bits.read_bits(8)? as u8,
590 bits.read_bits(8)? as u8,
591 bits.read_bits(8)? as u8,
592 ],
593 AddressType::Ipv6UniqueLocal => vec![
594 bits.read_bits(8)? as u8,
595 bits.read_bits(8)? as u8,
596 bits.read_bits(8)? as u8,
597 bits.read_bits(8)? as u8,
598 bits.read_bits(8)? as u8,
599 bits.read_bits(8)? as u8,
600 ],
601 AddressType::Ipv6Public => {
602 return Err(FourWordError::InvalidInput(
603 "Public IPv6 not supported".to_string(),
604 ));
605 }
606 };
607
608 let port = if bits.read_bits(1)? == 1 {
610 if bits.read_bits(1)? == 0 {
611 let code = bits.read_bits(4)? as u8;
613 compressor.port_compressor.decompress(&[code], 4)?
614 } else if bits.read_bits(1)? == 0 {
615 let code = bits.read_bits(8)? as u8;
617 compressor.port_compressor.decompress(&[code], 8)?
618 } else {
619 let port_value = bits.read_bits(16)?;
621 Some(port_value as u16)
622 }
623 } else {
624 None
625 };
626
627 let ip = compressor.decompress_address(addr_type, &addr_data)?;
628 Ok((ip, port))
629 }
630}
631
632struct BitWriter {
634 data: Vec<u8>,
635 current_byte: u8,
636 bits_in_current: usize,
637}
638
639impl BitWriter {
640 fn new() -> Self {
641 Self {
642 data: Vec::new(),
643 current_byte: 0,
644 bits_in_current: 0,
645 }
646 }
647
648 fn write_bits(&mut self, value: u32, num_bits: usize) {
649 let mut bits_to_write = num_bits;
650
651 while bits_to_write > 0 {
652 let bits_available = 8 - self.bits_in_current;
653 let bits_this_round = bits_to_write.min(bits_available);
654
655 let mask = (1 << bits_this_round) - 1;
656 let bits = ((value >> (bits_to_write - bits_this_round)) & mask) as u8;
657
658 self.current_byte = (self.current_byte << bits_this_round) | bits;
659 self.bits_in_current += bits_this_round;
660
661 if self.bits_in_current == 8 {
662 self.data.push(self.current_byte);
663 self.current_byte = 0;
664 self.bits_in_current = 0;
665 }
666
667 bits_to_write -= bits_this_round;
668 }
669 }
670
671 fn finish(mut self) -> Vec<u8> {
672 if self.bits_in_current > 0 {
673 self.current_byte <<= 8 - self.bits_in_current;
675 self.data.push(self.current_byte);
676 }
677 self.data
678 }
679
680 #[allow(dead_code)]
682 fn bit_count(&self) -> usize {
683 self.data.len() * 8 + self.bits_in_current
684 }
685}
686
687struct BitReader<'a> {
689 data: &'a [u8],
690 byte_index: usize,
691 bit_index: usize,
692}
693
694impl<'a> BitReader<'a> {
695 fn new(data: &'a [u8]) -> Self {
696 Self {
697 data,
698 byte_index: 0,
699 bit_index: 0,
700 }
701 }
702
703 fn read_bits(&mut self, num_bits: usize) -> Result<u32, FourWordError> {
704 let mut result = 0u32;
705 let mut bits_read = 0;
706
707 while bits_read < num_bits {
708 if self.byte_index >= self.data.len() {
709 return Err(FourWordError::InvalidInput(
710 "Insufficient data for bit reading".to_string(),
711 ));
712 }
713
714 let bits_available = 8 - self.bit_index;
715 let bits_to_read = (num_bits - bits_read).min(bits_available);
716
717 let mask = ((1 << bits_to_read) - 1) as u8;
718 let bits = (self.data[self.byte_index] >> (bits_available - bits_to_read)) & mask;
719
720 result = (result << bits_to_read) | (bits as u32);
721 bits_read += bits_to_read;
722
723 self.bit_index += bits_to_read;
724 if self.bit_index == 8 {
725 self.byte_index += 1;
726 self.bit_index = 0;
727 }
728 }
729
730 Ok(result)
731 }
732}
733
734#[cfg(test)]
735mod tests {
736 use super::*;
737
738 #[test]
739 fn test_ipv4_compression() {
740 let compressor = IpCompressor::new();
741
742 let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
744 let compressed = compressor.compress(&ip, Some(80)).unwrap();
745 assert!(compressed.total_bits <= 15); let ip = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100));
749 let compressed = compressor.compress(&ip, Some(443)).unwrap();
750 assert!(compressed.total_bits <= 23); let (decompressed_ip, decompressed_port) = compressor.decompress(&compressed).unwrap();
754 assert_eq!(decompressed_ip, ip);
755 assert_eq!(decompressed_port, Some(443));
756 }
757
758 #[test]
759 fn test_ipv6_compression() {
760 let compressor = IpCompressor::new();
761
762 let ip = IpAddr::V6(Ipv6Addr::LOCALHOST);
764 let compressed = compressor.compress(&ip, Some(22)).unwrap();
765 assert!(compressed.total_bits <= 8); let (decompressed_ip, decompressed_port) = compressor.decompress(&compressed).unwrap();
769 assert_eq!(decompressed_ip, ip);
770 assert_eq!(decompressed_port, Some(22));
771 }
772
773 #[test]
774 fn test_port_compression() {
775 let compressor = PortCompressor::new();
776
777 let (data, bits) = compressor.compress(Some(80));
779 assert_eq!(bits, 4);
780 assert_eq!(compressor.decompress(&data, bits).unwrap(), Some(80));
781
782 let (data, bits) = compressor.compress(Some(3389));
784 assert_eq!(bits, 8);
785 assert_eq!(compressor.decompress(&data, bits).unwrap(), Some(3389));
786
787 let (data, bits) = compressor.compress(Some(12345));
789 assert_eq!(bits, 16);
790 assert_eq!(compressor.decompress(&data, bits).unwrap(), Some(12345));
791 }
792
793 #[test]
794 fn test_bit_packing() {
795 let compressor = IpCompressor::new();
796
797 let ip = IpAddr::V4(Ipv4Addr::new(10, 20, 30, 40));
798 let compressed = compressor.compress(&ip, Some(8080)).unwrap();
799
800 let packed = compressed.pack();
802 assert!(packed.len() <= 6); let (unpacked_ip, unpacked_port) = CompressedAddress::unpack(&packed, &compressor).unwrap();
805 assert_eq!(unpacked_ip, ip);
806 assert_eq!(unpacked_port, Some(8080));
807 }
808}