@@ -3,6 +3,8 @@ use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
3
3
use fallible_iterator:: FallibleIterator ;
4
4
use std:: boxed:: Box as StdBox ;
5
5
use std:: error:: Error ;
6
+ use std:: io:: Read ;
7
+ use std:: net:: { IpAddr , Ipv4Addr , Ipv6Addr } ;
6
8
use std:: str;
7
9
8
10
use crate :: { write_nullable, FromUsize , IsNull , Oid } ;
@@ -16,6 +18,9 @@ const RANGE_UPPER_INCLUSIVE: u8 = 0b0000_0100;
16
18
const RANGE_LOWER_INCLUSIVE : u8 = 0b0000_0010 ;
17
19
const RANGE_EMPTY : u8 = 0b0000_0001 ;
18
20
21
+ const PGSQL_AF_INET : u8 = 2 ;
22
+ const PGSQL_AF_INET6 : u8 = 3 ;
23
+
19
24
/// Serializes a `BOOL` value.
20
25
#[ inline]
21
26
pub fn bool_to_sql ( v : bool , buf : & mut Vec < u8 > ) {
@@ -956,3 +961,86 @@ impl<'a> FallibleIterator for PathPoints<'a> {
956
961
( len, Some ( len) )
957
962
}
958
963
}
964
+
965
+ /// Serializes a Postgres inet.
966
+ #[ inline]
967
+ pub fn inet_to_sql ( addr : IpAddr , netmask : u8 , buf : & mut Vec < u8 > ) {
968
+ let family = match addr {
969
+ IpAddr :: V4 ( _) => PGSQL_AF_INET ,
970
+ IpAddr :: V6 ( _) => PGSQL_AF_INET6 ,
971
+ } ;
972
+ buf. push ( family) ;
973
+ buf. push ( netmask) ;
974
+ buf. push ( 0 ) ; // is_cidr
975
+ match addr {
976
+ IpAddr :: V4 ( addr) => {
977
+ buf. push ( 4 ) ;
978
+ buf. extend_from_slice ( & addr. octets ( ) ) ;
979
+ }
980
+ IpAddr :: V6 ( addr) => {
981
+ buf. push ( 16 ) ;
982
+ buf. extend_from_slice ( & addr. octets ( ) ) ;
983
+ }
984
+ }
985
+ }
986
+
987
+ /// Deserializes a Postgres inet.
988
+ #[ inline]
989
+ pub fn inet_from_sql ( mut buf : & [ u8 ] ) -> Result < Inet , StdBox < dyn Error + Sync + Send > > {
990
+ let family = buf. read_u8 ( ) ?;
991
+ let netmask = buf. read_u8 ( ) ?;
992
+ buf. read_u8 ( ) ?; // is_cidr
993
+ let len = buf. read_u8 ( ) ?;
994
+
995
+ let addr = match family {
996
+ PGSQL_AF_INET => {
997
+ if netmask > 32 {
998
+ return Err ( "invalid IPv4 netmask" . into ( ) ) ;
999
+ }
1000
+ if len != 4 {
1001
+ return Err ( "invalid IPv4 address length" . into ( ) ) ;
1002
+ }
1003
+ let mut addr = [ 0 ; 4 ] ;
1004
+ buf. read_exact ( & mut addr) ?;
1005
+ IpAddr :: V4 ( Ipv4Addr :: from ( addr) )
1006
+ }
1007
+ PGSQL_AF_INET6 => {
1008
+ if netmask > 128 {
1009
+ return Err ( "invalid IPv6 netmask" . into ( ) ) ;
1010
+ }
1011
+ if len != 16 {
1012
+ return Err ( "invalid IPv6 address length" . into ( ) ) ;
1013
+ }
1014
+ let mut addr = [ 0 ; 16 ] ;
1015
+ buf. read_exact ( & mut addr) ?;
1016
+ IpAddr :: V6 ( Ipv6Addr :: from ( addr) )
1017
+ }
1018
+ _ => return Err ( "invalid IP family" . into ( ) ) ,
1019
+ } ;
1020
+
1021
+ if !buf. is_empty ( ) {
1022
+ return Err ( "invalid buffer size" . into ( ) ) ;
1023
+ }
1024
+
1025
+ Ok ( Inet { addr, netmask } )
1026
+ }
1027
+
1028
+ /// A Postgres network address.
1029
+ pub struct Inet {
1030
+ addr : IpAddr ,
1031
+ netmask : u8 ,
1032
+ }
1033
+
1034
+ impl Inet {
1035
+ /// Returns the IP address.
1036
+ #[ inline]
1037
+ pub fn addr ( & self ) -> IpAddr {
1038
+ self . addr
1039
+ }
1040
+
1041
+ /// Returns the netmask.
1042
+ #[ inline]
1043
+ pub fn netmask ( & self ) -> u8 {
1044
+ self . netmask
1045
+ }
1046
+ }
0 commit comments