Skip to content

Commit

Permalink
IP address manipulation library.
Browse files Browse the repository at this point in the history
Three new library types:
`net.IpAddr`   - IPv4 or IPv6 address
`net.Ipv4Addr` - IPv4 address
`net.Ipv6Addr` - IPv6 address
  • Loading branch information
ryzhyk committed Feb 8, 2020
1 parent cd91e4d commit b5b650e
Show file tree
Hide file tree
Showing 35 changed files with 1,264 additions and 15 deletions.
4 changes: 2 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ test-tutorial:

# Test individual libraries

test-uuid:
test-libs:
extends: .install-ddlog
script:
- (cd test/datalog_tests &&
./run-test.sh uuid_test.dl release)
./test-libs.sh)

test-server_api:
script:
Expand Down
7 changes: 7 additions & 0 deletions lib/net/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Networking primitives for TCP/UDP communication.

This library provides networking functionality for the Transmission Control
and User Datagram Protocols, as well as types for IP and socket addresses.

Functions and data types in this library are bindings for functions and data
types in the `std::net` Rust module.
78 changes: 78 additions & 0 deletions lib/net/ipaddr.dl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* An IP address, either IPv4 or IPv6.
*
* This enum can contain either an Ipv4Addr or an Ipv6Addr, see their respective
* documentation for more details.
*
* The size of an IpAddr instance may vary depending on the target operating
* system.
*/

import net.ipv4
import net.ipv6

typedef IpAddr = IpAddrV4{addr4: Ipv4Addr}
| IpAddrV6{addr6: Ipv6Addr}

function ipaddr_from_ipv4addr(ipv4: Ipv4Addr): IpAddr = IpAddrV4{ipv4}
function ipaddr_from_ipv6addr(ipv6: Ipv6Addr): IpAddr = IpAddrV6{ipv6}

/* Returns true for the special 'unspecified' address.
*
* See the documentation for `ipv4_is_unspecified` and `ipv6_is_unspecified`
* for more details.
*/
function ipaddr_is_unspecified(addr: IpAddr): bool = {
match (addr) {
IpAddrV4{a} -> ipv4_is_unspecified(a),
IpAddrV6{a} -> ipv6_is_unspecified(a)
}
}

/* Returns true if this is a loopback address.
*
* See the documentation for `ipv4_is_loopback` and `ipv6_is_loopback` for
* more details.
*/
function ipaddr_is_loopback(addr: IpAddr): bool = {
match (addr) {
IpAddrV4{a} -> ipv4_is_loopback(a),
IpAddrV6{a} -> ipv6_is_loopback(a)
}
}

/* Returns true if this is a multicast address.
*
* See the documentation for `ipv4_is_multicast and `ipv6_is_multicast for
* more details.
*/
function ipaddr_is_multicast(addr: IpAddr): bool = {
match (addr) {
IpAddrV4{a} -> ipv4_is_multicast(a),
IpAddrV6{a} -> ipv6_is_multicast(a)
}
}

/* Returns true if this address is an IPv4 address, and false otherwise. */
function ipaddr_is_ipv4(addr: IpAddr): bool = {
match (addr) {
IpAddrV4{} -> true,
IpAddrV6{} -> false
}
}

/* Returns true if this address is an IPv6 address, and false otherwise. */
function ipaddr_is_ipv6(addr: IpAddr): bool = {
match (addr) {
IpAddrV4{} -> false,
IpAddrV6{} -> true
}
}

/* Format IP address.
*/
function ipAddr2string(addr: IpAddr): string = {
match (addr) {
IpAddrV4{a} -> ipv4Addr2string(a),
IpAddrV6{a} -> ipv6Addr2string(a)
}
}
126 changes: 126 additions & 0 deletions lib/net/ipv4.dl
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/* An IPv4 address.
*
* IPv4 addresses are defined as 32-bit integers in IETF RFC 791. They are
* usually represented as four octets.
*
* See IpAddr for a type encompassing both IPv4 and IPv6 addresses.
*
* The size of an Ipv4Addr struct may vary depending on the target operating
* system.
*/

import net.ipv6

extern type Ipv4Addr

/* Creates a new IPv4 address from four eight-bit octets.
*
* The result will represent the IP address a.b.c.d.
*/
extern function ipv4_new(a: u8, b: u8, c: u8, d: u8): Ipv4Addr

/* Creates a new IPv4 address from a vector of octets.
*
* Returns None if the length of `octets` is not 4.
*/
extern function ipv4_from_octet_vec(octets: Vec<u8>): Option<Ipv4Addr>

/* Converts a host byte order u32 into an Ipv4Addr.
*/
extern function ipv4_from_u32(ip: u32): Ipv4Addr

/* Parse IPv4 address string in decimal notation, divided by .
* (this is called "dot-decimal notation").
*/
extern function ipv4_from_str(s: string): Result<Ipv4Addr, string>

/* Format IPv4 address using dot-decimal notation.
*/
extern function ipv4Addr2string(addr: Ipv4Addr): string

/* An IPv4 address with the address pointing to localhost: 127.0.0.1.
*/
extern function iPV4_LOCALHOST(): Ipv4Addr

/* An IPv4 address representing an unspecified address: 0.0.0.0.
*/
extern function iPV4_UNSPECIFIED(): Ipv4Addr

/* An IPv4 address representing the broadcast address: 255.255.255.255.
*/
extern function iPV4_BROADCAST(): Ipv4Addr

/* Returns the four eight-bit integers that make up this address.
*/
extern function ipv4_octets(addr: Ipv4Addr): (u8, u8, u8, u8)

/* Returns a vector of four eight-bit integers the IPv4 address consists of.
*/
extern function ipv4_octet_vec(addr: Ipv4Addr): Vec<u8>

/* Returns true for the special 'unspecified' address (0.0.0.0).
*
* This property is defined in UNIX Network Programming, Second Edition,
* W. Richard Stevens, p. 891; see also ip7.
*/
extern function ipv4_is_unspecified(addr: Ipv4Addr): bool

/* Returns true if this is a loopback address (127.0.0.0/8).
*
* This property is defined by IETF RFC 1122.
*/
extern function ipv4_is_loopback(addr: Ipv4Addr): bool

/* Returns true if this is a private address.
*
* The private address ranges are defined in IETF RFC 1918 and include:
* - 10.0.0.0/8
* - 172.16.0.0/12
* - 192.168.0.0/16
*/
extern function ipv4_is_private(addr: Ipv4Addr): bool

/* Returns true if the address is link-local (169.254.0.0/16).
*
* This property is defined by IETF RFC 3927.
*/
extern function ipv4_is_link_local(addr: Ipv4Addr): bool

/* Returns true if this is a multicast address (224.0.0.0/4).
*
* Multicast addresses have a most significant octet between 224 and 239, and
* is defined by IETF RFC 5771.
*/
extern function ipv4_is_multicast(addr: Ipv4Addr): bool

/* Returns true if this is a broadcast address (255.255.255.255).
*
* A broadcast address has all octets set to 255 as defined in IETF RFC 919.
*/
extern function ipv4_is_broadcast(addr: Ipv4Addr): bool

/* Returns true if this address is in a range designated for documentation.
*
* This is defined in IETF RFC 5737:
*
* - 192.0.2.0/24 (TEST-NET-1)
* - 198.51.100.0/24 (TEST-NET-2)
* - 203.0.113.0/24 (TEST-NET-3)
*/
extern function ipv4_is_documentation(addr: Ipv4Addr): bool

/* Converts this address to an IPv4-compatible IPv6 address.
*
* a.b.c.d becomes ::a.b.c.d
*/
extern function ipv4_to_ipv6_compatible(addr: Ipv4Addr): Ipv6Addr

/* Converts this address to an IPv4-mapped IPv6 address.
*
* a.b.c.d becomes ::ffff:a.b.c.d
*/
extern function ipv4_to_ipv6_mapped(addr: Ipv4Addr): Ipv6Addr

/* Converts an Ipv4Addr into a host byte order u32.
*/
extern function ipv4_to_u32(addr: Ipv4Addr): u32
166 changes: 166 additions & 0 deletions lib/net/ipv4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use differential_datalog::record::FromRecord;
use differential_datalog::record::IntoRecord;
use differential_datalog::record::Mutator;
use differential_datalog::record::Record;
use serde::de::Deserialize;
use serde::de::Deserializer;
use serde::ser::Serialize;
use serde::ser::Serializer;
use std::net::Ipv4Addr;
use std::str::FromStr;

#[derive(Eq, Ord, Clone, Hash, PartialEq, PartialOrd)]
pub struct net_ipv4_Ipv4Addr(Ipv4Addr);

impl net_ipv4_Ipv4Addr {
pub fn new(addr: Ipv4Addr) -> Self {
net_ipv4_Ipv4Addr(addr)
}
}

impl Deref for net_ipv4_Ipv4Addr {
type Target = Ipv4Addr;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Default for net_ipv4_Ipv4Addr {
fn default() -> net_ipv4_Ipv4Addr {
net_ipv4_iPV4_UNSPECIFIED()
}
}

impl fmt::Display for net_ipv4_Ipv4Addr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", net_ipv4_ipv4_to_u32(self))
}
}

impl fmt::Debug for net_ipv4_Ipv4Addr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}

impl Serialize for net_ipv4_Ipv4Addr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
net_ipv4_ipv4_to_u32(self).serialize(serializer)
}
}

impl<'de> Deserialize<'de> for net_ipv4_Ipv4Addr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
u32::deserialize(deserializer).map(|x| net_ipv4_ipv4_from_u32(&x))
}
}

impl FromRecord for net_ipv4_Ipv4Addr {
fn from_record(val: &Record) -> Result<Self, String> {
u32::from_record(val).map(|x| net_ipv4_ipv4_from_u32(&x))
}
}

impl IntoRecord for net_ipv4_Ipv4Addr {
fn into_record(self) -> Record {
net_ipv4_ipv4_to_u32(&self).into_record()
}
}

impl Mutator<net_ipv4_Ipv4Addr> for Record {
fn mutate(&self, addr: &mut net_ipv4_Ipv4Addr) -> Result<(), String> {
net_ipv4_Ipv4Addr::from_record(self).map(|a| *addr = a)
}
}

pub fn net_ipv4_ipv4_new(a: &u8, b: &u8, c: &u8, d: &u8) -> net_ipv4_Ipv4Addr {
net_ipv4_Ipv4Addr(Ipv4Addr::new(*a, *b, *c, *d))
}

pub fn net_ipv4_ipv4_from_u32(ip: &u32) -> net_ipv4_Ipv4Addr {
net_ipv4_Ipv4Addr(Ipv4Addr::from(*ip))
}

pub fn net_ipv4_ipv4_from_octet_vec(octets: &std_Vec<u8>) -> std_Option<net_ipv4_Ipv4Addr> {
if octets.len() != 4 {
return std_Option::std_None;
};
std_Option::std_Some {
x: net_ipv4_Ipv4Addr::new(Ipv4Addr::from([octets[0], octets[1], octets[2], octets[3]])),
}
}
pub fn net_ipv4_ipv4_from_str(s: &String) -> std_Result<net_ipv4_Ipv4Addr, String> {
res2std(Ipv4Addr::from_str(&*s).map(net_ipv4_Ipv4Addr))
}

pub fn net_ipv4_ipv4Addr2string(addr: &net_ipv4_Ipv4Addr) -> String {
(**addr).to_string()
}

pub fn net_ipv4_iPV4_LOCALHOST() -> net_ipv4_Ipv4Addr {
net_ipv4_Ipv4Addr(Ipv4Addr::LOCALHOST)
}

pub fn net_ipv4_iPV4_UNSPECIFIED() -> net_ipv4_Ipv4Addr {
net_ipv4_Ipv4Addr(Ipv4Addr::UNSPECIFIED)
}

pub fn net_ipv4_iPV4_BROADCAST() -> net_ipv4_Ipv4Addr {
net_ipv4_Ipv4Addr(Ipv4Addr::BROADCAST)
}

pub fn net_ipv4_ipv4_octets(addr: &net_ipv4_Ipv4Addr) -> (u8, u8, u8, u8) {
let octets = addr.octets();
(octets[0], octets[1], octets[2], octets[3])
}

pub fn net_ipv4_ipv4_octet_vec(addr: &net_ipv4_Ipv4Addr) -> std_Vec<u8> {
std_Vec::from(addr.octets().as_ref())
}

pub fn net_ipv4_ipv4_is_unspecified(addr: &net_ipv4_Ipv4Addr) -> bool {
addr.is_unspecified()
}

pub fn net_ipv4_ipv4_is_loopback(addr: &net_ipv4_Ipv4Addr) -> bool {
addr.is_loopback()
}

pub fn net_ipv4_ipv4_is_private(addr: &net_ipv4_Ipv4Addr) -> bool {
addr.is_private()
}

pub fn net_ipv4_ipv4_is_link_local(addr: &net_ipv4_Ipv4Addr) -> bool {
addr.is_link_local()
}

pub fn net_ipv4_ipv4_is_multicast(addr: &net_ipv4_Ipv4Addr) -> bool {
addr.is_multicast()
}

pub fn net_ipv4_ipv4_is_broadcast(addr: &net_ipv4_Ipv4Addr) -> bool {
addr.is_broadcast()
}

pub fn net_ipv4_ipv4_is_documentation(addr: &net_ipv4_Ipv4Addr) -> bool {
addr.is_documentation()
}

pub fn net_ipv4_ipv4_to_ipv6_compatible(addr: &net_ipv4_Ipv4Addr) -> net_ipv6_Ipv6Addr {
net_ipv6_Ipv6Addr::new(addr.to_ipv6_compatible())
}

pub fn net_ipv4_ipv4_to_ipv6_mapped(addr: &net_ipv4_Ipv4Addr) -> net_ipv6_Ipv6Addr {
net_ipv6_Ipv6Addr::new(addr.to_ipv6_mapped())
}

pub fn net_ipv4_ipv4_to_u32(addr: &net_ipv4_Ipv4Addr) -> u32 {
u32::from(**addr)
}

0 comments on commit b5b650e

Please sign in to comment.