diff --git a/builder/vmware/common/driver_parser.go b/builder/vmware/common/driver_parser.go index cd63c1345..745de40c4 100644 --- a/builder/vmware/common/driver_parser.go +++ b/builder/vmware/common/driver_parser.go @@ -1,15 +1,19 @@ package common import ( + "bytes" + "encoding/hex" "fmt" "log" "math" "net" "os" "reflect" + "regexp" "sort" "strconv" "strings" + "time" ) /** low-level parsing */ @@ -2233,3 +2237,119 @@ func consumeOpenClosePair(openByte, closeByte byte, in chan byte) ([]byte, chan // the openByte and closeByte pair. return result, out } + +// Basic decoding of a dhcpd lease address +func decodeDhcpdLeaseBytes(input string) ([]byte, error) { + processed := &bytes.Buffer{} + + // Split the string into pieces as we'll need to validate it. + for _, item := range strings.Split(input, ":") { + if len(item) != 2 { + return []byte{}, fmt.Errorf("bytes are not well-formed (%v)", input) + } + processed.WriteString(item) + } + + length := hex.DecodedLen(processed.Len()) + + // Decode the processed data into the result... + result := make([]byte, length) + if n, err := hex.Decode(result, processed.Bytes()); err != nil { + return []byte{}, err + + // Check that our decode length corresponds to what was intended + } else if n != length { + return []byte{}, fmt.Errorf("expected to decode %d bytes, got %d instead", length, n) + } + + // ...and then return it. + return result, nil +} + +/*** Dhcp Leases */ +type dhcpLeaseEntry struct { + address string + starts, ends time.Time + ether, uid []byte + extra []string +} + +func readDhcpdLeaseEntry(in chan byte) (entry *dhcpLeaseEntry) { + + // Build the regexes we'll use to legitimately parse each item + ipLineRe := regexp.MustCompile(`^lease (.+?) {$`) + startTimeLineRe := regexp.MustCompile(`^\s*starts \d (.+?);$`) + endTimeLineRe := regexp.MustCompile(`^\s*ends \d (.+?);$`) + macLineRe := regexp.MustCompile(`^\s*hardware ethernet (.+?);$`) + uidLineRe := regexp.MustCompile(`^\s*uid (.+?);$`) + + /// Read up to the lease item and validate that it actually matches + lease, ch := consumeOpenClosePair('{', '}', in) + + matches := ipLineRe.FindStringSubmatch(string(lease)) + if matches == nil { + return nil + } + + // If we found a lease match and we're definitely beginning a lease + // entry, then create our storage. + if by, ok := <-ch; ok && by == '{' { + entry = &dhcpLeaseEntry{address: matches[1]} + + // Otherwise we bail. + } else { + return nil + } + + /// Now we can parse the inside of the block. + for insideBraces := true; insideBraces; { + item, ok := consumeUntilSentinel(';', in) + item_s := string(item) + + if !ok { + insideBraces = false + } + + // Parse out the start time + matches = startTimeLineRe.FindStringSubmatch(item_s) + if matches != nil { + entry.starts, _ = time.Parse("2006/01/02 15:04:05", matches[1]) + continue + } + + // Parse out the end time + matches = endTimeLineRe.FindStringSubmatch(item_s) + if matches != nil { + entry.ends, _ = time.Parse("2006/01/02 15:04:05", matches[1]) + continue + } + + // Parse out the hardware ethernet + matches = macLineRe.FindStringSubmatch(item_s) + if matches != nil { + entry.ether, _ = decodeDhcpdLeaseBytes(item_s) + continue + } + + // Parse out the uid + matches = uidLineRe.FindStringSubmatch(item_s) + if matches != nil { + entry.uid, _ = decodeDhcpdLeaseBytes(item_s) + continue + } + + // Just stash it for now because we have no idea what it is. + entry.extra = append(entry.extra, strings.TrimSpace(item_s)) + } + + return entry +} + +func ReadDhcpdLeases(fd *os.File) ([]dhcpLeaseEntry, error) { + fch := consumeFile(fd) + uncommentedch := uncomment(fch) + wch := filterOutCharacters([]byte{'\n', '\r', '\v'}, uncommentedch) + close(wch) + + return []dhcpLeaseEntry{}, fmt.Errorf("Not implemented yet!") +} diff --git a/builder/vmware/common/driver_parser_test.go b/builder/vmware/common/driver_parser_test.go index b52e6739e..1d2e489ca 100644 --- a/builder/vmware/common/driver_parser_test.go +++ b/builder/vmware/common/driver_parser_test.go @@ -634,3 +634,51 @@ func TestParserCombinators(t *testing.T) { } } } + +func TestParserDhcpdLeaseBytesDecoder(t *testing.T) { + test_1 := "00:0d:0e:0a:0d:00" + expected_1 := []byte{0, 13, 14, 10, 13, 0} + + result, err := decodeDhcpdLeaseBytes(test_1) + if err != nil { + t.Errorf("unable to decode address: %s", err) + } + if bytes.Compare(result, expected_1) != 0 { + t.Errorf("expected %v, got %v", expected_1, result) + } + + test_2 := "11" + expected_2 := []byte{17} + + result, err = decodeDhcpdLeaseBytes(test_2) + if err != nil { + t.Errorf("unable to decode address: %s", err) + } + if bytes.Compare(result, expected_2) != 0 { + t.Errorf("expected %v, got %v", expected_2, result) + } + + failtest_1 := "" + result, err = decodeDhcpdLeaseBytes(failtest_1) + if err == nil { + t.Errorf("expected decoding error: %s", err) + } + + failtest_2 := "000000" + result, err = decodeDhcpdLeaseBytes(failtest_2) + if err == nil { + t.Errorf("expected decoding error: %s", err) + } + + failtest_3 := "000:00" + result, err = decodeDhcpdLeaseBytes(failtest_3) + if err == nil { + t.Errorf("expected decoding error: %s", err) + } + + failtest_4 := "00:00:" + result, err = decodeDhcpdLeaseBytes(failtest_4) + if err == nil { + t.Errorf("expected decoding error: %s", err) + } +}