Skip to content
This repository has been archived by the owner on Aug 7, 2020. It is now read-only.

Commit

Permalink
Support non-standard IPv4 representations
Browse files Browse the repository at this point in the history
... and allow IPv4 Addresses to be casted to uint32s

Signed-off-by: Ariel Abreu <[email protected]>
  • Loading branch information
facekapow committed Oct 20, 2019
1 parent 6e638ae commit 5aa43bc
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 17 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![License](https://img.shields.io/github/license/alta-lang/ip?color=%23428bff)](LICENSE)

An IP address parsing/serialization library for Alta.
Fully supports IPv6 shorthand syntax.
Fully supports (standard) IPv6 shorthand syntax and (non-standard) IPv4 shorthand.

## Documentation
Check out the [docs](docs).
Expand Down Expand Up @@ -100,3 +100,11 @@ if userInputAddr.isIPv4 {
# it's IPv6
}
```

## Notes
### IPv4
According to the standards, IPv4 address should only be represented as either a single, 32-bit decimal or 4 8-bit decimals. These two forms look like `a` or `a.b.c.d`. However, the [inet_aton](https://linux.die.net/man/3/inet_aton) function commonly used on Linux (and some other Unix OSes like macOS) also supports two more address representations: `a.b` and `a.b.c`.

The first form (`a.b`) is the first octet (i.e. 8-bit decimal) followed by a 24-bit decimal representing the last three octects of the address. The second form (`a.b.c`) consists of the first two octets followed by a 16-bit value representing the last two octets.

Note that for all the forms with multiple parts representing the final decimal (`a.b`, `a.b.c`, and `a.b.c.d`), the octets are orded in LE (little-endian) order, meaning that `192` in `192.168.1.1` represents the highest octet (bits 24-32) in the full 32-bit decimal value for the address, for example.
70 changes: 55 additions & 15 deletions main.alta
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Vector from "vector"
import uint8, uint16, Size, SizeMaximum from "types"
import uint8, uint16, uint32, Size, SizeMaximum, UInt32ToUInt8, UInt16ToUInt8 from "types"
import Exception from "exceptions"
import parseNumber, numberToString from "util"
import String from "string"
Expand All @@ -26,6 +26,15 @@ export class InvalidComponentIndex extends Exception {}
# * If more than 8 components are found
export class InvalidAddress extends Exception {}

# @brief An invalid operation was performed on the given address
# @desc An exception thrown when trying to perform an operation
# on an Address that doesn't support that operation. This
# usually means you've tried to use an IPv4 Address like
# an IPv6 one or vice versa (for example, trying to coerce
# an IPv6 Address to a uint32, something only IPv4 Addresses
# can do).
export class InvalidAddressType extends Exception {}

export class Address {
private var _isV6 = false
private var _components = new Vector<uint16>(6)
Expand Down Expand Up @@ -53,16 +62,10 @@ export class Address {
let found = false
for i: Size in 0..address.length {
if address[i] == ':' {
found = true
this._isV6 = true
break
} else if address[i] == '.' {
found = true
break
}
}
if !found
throw new InvalidAddress
for i: uint8 in 0..(this._isV6 ? 8 : 4) {
this._components.push(0)
}
Expand Down Expand Up @@ -118,18 +121,42 @@ export class Address {
let second = address.indexOf('.', after: first)
let third = address.indexOf('.', after: second)

if first == SizeMaximum || second == SizeMaximum || third == SizeMaximum {
if first != SizeMaximum && second != SizeMaximum && third != SizeMaximum && address.indexOf('.', after: third) != SizeMaximum {
throw new InvalidAddress
}

if address.indexOf('.', after: third) != SizeMaximum {
throw new InvalidAddress
if first == SizeMaximum {
# a (uint32)
let num: UInt32ToUInt8 = parseNumber<uint32>(address)
this._components[0] = num.part4
this._components[1] = num.part3
this._components[2] = num.part2
this._components[3] = num.part1
} else if second == SizeMaximum {
# a.b (uint8.uint24)
# no 24-bit integer type so just upgrade it to uint32
let num: UInt32ToUInt8 = parseNumber<uint32>(address.substring(from: first + 1, to: address.length))
this._components[0] = parseNumber<uint8>(address.substring(from: 0, to: first))
this._components[1] = num.part3
this._components[2] = num.part2
this._components[3] = num.part1
} else if third == SizeMaximum {
# a.b.c (uint8.uint8.uint16)
let num: UInt16ToUInt8 = parseNumber<uint16>(address.substring(from: second + 1, to: address.length))
this._components[0] = parseNumber<uint8>(address.substring(from: 0, to: first))
this._components[1] = parseNumber<uint8>(address.substring(from: first + 1, to: second))
this._components[2] = num.part2
this._components[3] = num.part1
} else {
# a.b.c.d (uint8.uint8.uint.uint8)
# this is the standard notation for IPv4 addresses
# the others have just been added for compatibility with conventions
# established by IP parsing functions in other languages (such as `inet_aton`)
this._components[0] = parseNumber<uint16>(address.substring(from: 0, to: first))
this._components[1] = parseNumber<uint16>(address.substring(from: first + 1, to: second))
this._components[2] = parseNumber<uint16>(address.substring(from: second + 1, to: third))
this._components[3] = parseNumber<uint16>(address.substring(from: third + 1, to: address.length))
}

this._components[0] = parseNumber<uint16>(address.substring(from: 0, to: first))
this._components[1] = parseNumber<uint16>(address.substring(from: first + 1, to: second))
this._components[2] = parseNumber<uint16>(address.substring(from: second + 1, to: third))
this._components[3] = parseNumber<uint16>(address.substring(from: third + 1, to: address.length))
}
}

Expand Down Expand Up @@ -230,4 +257,17 @@ export class Address {
numberToString<uint16>(this._components[3], 10)
}
}

public to uint32 {
if this._isV6
throw new InvalidAddressType

let num: UInt32ToUInt8 = 0
num.part1 = this._components[3]
num.part2 = this._components[2]
num.part3 = this._components[1]
num.part4 = this._components[0]

return num
}
}
2 changes: 1 addition & 1 deletion package.alta.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name: ip
version: 1.0.0
version: 1.1.0
type: lib

0 comments on commit 5aa43bc

Please sign in to comment.