mapping completed

This commit is contained in:
Hayden Parker
2016-02-14 23:35:45 -08:00
parent 9d6560b94d
commit 9ccd358086

View File

@ -1,17 +1,44 @@
package common package common
/*
I2P Mapping
https://geti2p.net/en/docs/spec/common-structures#type_Mapping
Accurate for version 0.9.24
+----+----+----+----+----+----+----+----+
| size |key_string (len + data) | = |
+----+----+----+----+----+----+----+----+
| val_string (len + data) | ; | ...
+----+----+----+----+----+----+----+
size :: Integer
length -> 2 bytes
Total number of bytes that follow
key_string :: String
A string (one byte length followed by UTF-8 encoded characters)
= :: A single byte containing '='
val_string :: String
A string (one byte length followed by UTF-8 encoded characters)
; :: A single byte containing ';'
*/
import ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
log "github.com/Sirupsen/logrus"
"sort" "sort"
) )
type Mapping []byte type Mapping []byte
// Parsed key-values pairs inside a Mapping.
type MappingValues [][2]String type MappingValues [][2]String
// //
// Returns the values contained in a Mapping in // Returns the values contained in a Mapping in the form of a MappingValues.
// the form of a MappingValues.
// //
func (mapping Mapping) Values() (map_values MappingValues, errs []error) { func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
var str String var str String
@ -19,11 +46,24 @@ func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
var err error var err error
length := Integer(remainder[:2]) length := Integer(remainder[:2])
inferred_length := length + 2
remainder = remainder[2:] remainder = remainder[2:]
mapping_len := len(mapping) mapping_len := len(mapping)
if mapping_len > length+2 { if mapping_len > inferred_length {
log.WithFields(log.Fields{
"mappnig_bytes_length": mapping_len,
"mapping_length_field": length,
"expected_bytes_length": inferred_length,
"reason": "data longer than expected",
}).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: data exists beyond length of mapping")) errs = append(errs, errors.New("warning parsing mapping: data exists beyond length of mapping"))
} else if length+2 > mapping_len { } else if inferred_length > mapping_len {
log.WithFields(log.Fields{
"mappnig_bytes_length": mapping_len,
"mapping_length_field": length,
"expected_bytes_length": inferred_length,
"reason": "data shorter than expected",
}).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: mapping length exceeds provided data")) errs = append(errs, errors.New("warning parsing mapping: mapping length exceeds provided data"))
} }
@ -39,6 +79,9 @@ func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
} }
} }
if !beginsWith(remainder, 0x3d) { if !beginsWith(remainder, 0x3d) {
log.WithFields(log.Fields{
"reason": "expected =",
}).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected =")) errs = append(errs, errors.New("mapping format violation, expected ="))
return return
} }
@ -55,13 +98,15 @@ func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
} }
} }
if !beginsWith(remainder, 0x3b) { if !beginsWith(remainder, 0x3b) {
log.WithFields(log.Fields{
"reason": "expected ;",
}).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected ;")) errs = append(errs, errors.New("mapping format violation, expected ;"))
return return
} }
remainder = remainder[1:] remainder = remainder[1:]
// Append the key-value pair and break // Append the key-value pair and break if there is no more data to read
// if there is no more data to read
map_values = append(map_values, [2]String{key_str, val_str}) map_values = append(map_values, [2]String{key_str, val_str})
if len(remainder) == 0 { if len(remainder) == 0 {
break break
@ -71,7 +116,7 @@ func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
} }
// //
// Returns true if two keys in a mapping are identical // Return true if two keys in a mapping are identical.
// //
func (mapping Mapping) HasDuplicateKeys() bool { func (mapping Mapping) HasDuplicateKeys() bool {
seen_values := make(map[string]bool) seen_values := make(map[string]bool)
@ -88,12 +133,10 @@ func (mapping Mapping) HasDuplicateKeys() bool {
} }
// //
// ValuesToMapping takes a MappingValue struct and // Convert a MappingValue struct to a Mapping. The values are first
// returns a Mapping. The values are sorted in the // sorted in the order defined in mappingOrder.
// order defined in mappingOrder.
// //
func ValuesToMapping(values MappingValues) Mapping { func ValuesToMapping(values MappingValues) (mapping Mapping) {
var mapping Mapping
mappingOrder(values) mappingOrder(values)
for _, kv_pair := range values { for _, kv_pair := range values {
key_string := kv_pair[0] key_string := kv_pair[0]
@ -106,12 +149,11 @@ func ValuesToMapping(values MappingValues) Mapping {
len_bytes := make([]byte, 2) len_bytes := make([]byte, 2)
binary.BigEndian.PutUint16(len_bytes, uint16(map_len)) binary.BigEndian.PutUint16(len_bytes, uint16(map_len))
mapping = append(len_bytes, mapping...) mapping = append(len_bytes, mapping...)
return mapping return
} }
// //
// This function takes a map of unformatted strings // Convert a Go map of unformatted strings to a sorted Mapping.
// and returns a Mapping.
// //
func GoMapToMapping(gomap map[string]string) (mapping Mapping, err error) { func GoMapToMapping(gomap map[string]string) (mapping Mapping, err error) {
map_vals := MappingValues{} map_vals := MappingValues{}
@ -156,10 +198,8 @@ func (set ByKey) Less(i, j int) bool {
} }
// //
// I2P Mappings require consistent order for // I2P Mappings require consistent order for for cryptographic signing, and sorting
// for cryptographic signing, and sorting // by keys. When new Mappings are created, they are stable sorted first by values
// by keys. When new Mappings are created,
// they are stable sorted first by values
// than by keys to ensure a consistent order. // than by keys to ensure a consistent order.
// //
func mappingOrder(values MappingValues) { func mappingOrder(values MappingValues) {
@ -167,10 +207,17 @@ func mappingOrder(values MappingValues) {
sort.Stable(ByKey(values)) sort.Stable(ByKey(values))
} }
//
// Check if the string parsing error indicates that the Mapping
// should no longer be parsed.
//
func stopValueRead(err error) bool { func stopValueRead(err error) bool {
return err.Error() == "error parsing string: zero length" return err.Error() == "error parsing string: zero length"
} }
//
// Determine if the first byte in a slice of bytes is the provided byte.
//
func beginsWith(bytes []byte, chr byte) bool { func beginsWith(bytes []byte, chr byte) bool {
return len(bytes) != 0 && return len(bytes) != 0 &&
bytes[0] == chr bytes[0] == chr