github.com/mitchellh/packer@v1.3.2/builder/vmware/common/driver_parser.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"math"
     8  	"net"
     9  	"os"
    10  	"reflect"
    11  	"sort"
    12  	"strconv"
    13  	"strings"
    14  )
    15  
    16  type sentinelSignaller chan struct{}
    17  
    18  /** low-level parsing */
    19  // strip the comments and extraneous newlines from a byte channel
    20  func uncomment(eof sentinelSignaller, in <-chan byte) (chan byte, sentinelSignaller) {
    21  	out := make(chan byte)
    22  	eoc := make(sentinelSignaller)
    23  
    24  	go func(in <-chan byte, out chan byte) {
    25  		var endofline bool
    26  		for stillReading := true; stillReading; {
    27  			select {
    28  			case <-eof:
    29  				stillReading = false
    30  			case ch := <-in:
    31  				switch ch {
    32  				case '#':
    33  					endofline = true
    34  				case '\n':
    35  					if endofline {
    36  						endofline = false
    37  					}
    38  				}
    39  				if !endofline {
    40  					out <- ch
    41  				}
    42  			}
    43  		}
    44  		close(eoc)
    45  	}(in, out)
    46  	return out, eoc
    47  }
    48  
    49  // convert a byte channel into a channel of pseudo-tokens
    50  func tokenizeDhcpConfig(eof sentinelSignaller, in chan byte) (chan string, sentinelSignaller) {
    51  	var ch byte
    52  	var state string
    53  	var quote bool
    54  
    55  	eot := make(sentinelSignaller)
    56  
    57  	out := make(chan string)
    58  	go func(out chan string) {
    59  		for stillReading := true; stillReading; {
    60  			select {
    61  			case <-eof:
    62  				stillReading = false
    63  
    64  			case ch = <-in:
    65  				if quote {
    66  					if ch == '"' {
    67  						out <- state + string(ch)
    68  						state, quote = "", false
    69  						continue
    70  					}
    71  					state += string(ch)
    72  					continue
    73  				}
    74  
    75  				switch ch {
    76  				case '"':
    77  					quote = true
    78  					state += string(ch)
    79  					continue
    80  
    81  				case '\r':
    82  					fallthrough
    83  				case '\n':
    84  					fallthrough
    85  				case '\t':
    86  					fallthrough
    87  				case ' ':
    88  					if len(state) == 0 {
    89  						continue
    90  					}
    91  					out <- state
    92  					state = ""
    93  
    94  				case '{':
    95  					fallthrough
    96  				case '}':
    97  					fallthrough
    98  				case ';':
    99  					if len(state) > 0 {
   100  						out <- state
   101  					}
   102  					out <- string(ch)
   103  					state = ""
   104  
   105  				default:
   106  					state += string(ch)
   107  				}
   108  			}
   109  		}
   110  		if len(state) > 0 {
   111  			out <- state
   112  		}
   113  		close(eot)
   114  	}(out)
   115  	return out, eot
   116  }
   117  
   118  /** mid-level parsing */
   119  type tkParameter struct {
   120  	name    string
   121  	operand []string
   122  }
   123  
   124  func (e *tkParameter) String() string {
   125  	var values []string
   126  	for _, val := range e.operand {
   127  		values = append(values, val)
   128  	}
   129  	return fmt.Sprintf("%s [%s]", e.name, strings.Join(values, ","))
   130  }
   131  
   132  type tkGroup struct {
   133  	parent *tkGroup
   134  	id     tkParameter
   135  
   136  	groups []*tkGroup
   137  	params []tkParameter
   138  }
   139  
   140  func (e *tkGroup) String() string {
   141  	var id []string
   142  
   143  	id = append(id, e.id.name)
   144  	for _, val := range e.id.operand {
   145  		id = append(id, val)
   146  	}
   147  
   148  	var config []string
   149  	for _, val := range e.params {
   150  		config = append(config, val.String())
   151  	}
   152  	return fmt.Sprintf("%s {\n%s\n}", strings.Join(id, " "), strings.Join(config, "\n"))
   153  }
   154  
   155  // convert a channel of pseudo-tokens into an tkParameter struct
   156  func parseTokenParameter(in chan string) tkParameter {
   157  	var result tkParameter
   158  	for {
   159  		token := <-in
   160  		if result.name == "" {
   161  			result.name = token
   162  			continue
   163  		}
   164  		switch token {
   165  		case "{":
   166  			fallthrough
   167  		case "}":
   168  			fallthrough
   169  		case ";":
   170  			goto leave
   171  		default:
   172  			result.operand = append(result.operand, token)
   173  		}
   174  	}
   175  leave:
   176  	return result
   177  }
   178  
   179  // convert a channel of pseudo-tokens into an tkGroup tree */
   180  func parseDhcpConfig(eof sentinelSignaller, in chan string) (tkGroup, error) {
   181  	var tokens []string
   182  	var result tkGroup
   183  
   184  	toParameter := func(tokens []string) tkParameter {
   185  		out := make(chan string)
   186  		go func(out chan string) {
   187  			for _, v := range tokens {
   188  				out <- v
   189  			}
   190  			out <- ";"
   191  		}(out)
   192  		return parseTokenParameter(out)
   193  	}
   194  
   195  	for stillReading, currentgroup := true, &result; stillReading; {
   196  		select {
   197  		case <-eof:
   198  			stillReading = false
   199  
   200  		case tk := <-in:
   201  			switch tk {
   202  			case "{":
   203  				grp := &tkGroup{parent: currentgroup}
   204  				grp.id = toParameter(tokens)
   205  				currentgroup.groups = append(currentgroup.groups, grp)
   206  				currentgroup = grp
   207  			case "}":
   208  				if currentgroup.parent == nil {
   209  					return tkGroup{}, fmt.Errorf("Unable to close the global declaration")
   210  				}
   211  				if len(tokens) > 0 {
   212  					return tkGroup{}, fmt.Errorf("List of tokens was left unterminated : %v", tokens)
   213  				}
   214  				currentgroup = currentgroup.parent
   215  			case ";":
   216  				arg := toParameter(tokens)
   217  				currentgroup.params = append(currentgroup.params, arg)
   218  			default:
   219  				tokens = append(tokens, tk)
   220  				continue
   221  			}
   222  			tokens = []string{}
   223  		}
   224  	}
   225  	return result, nil
   226  }
   227  
   228  func tokenizeNetworkMapConfig(eof sentinelSignaller, in chan byte) (chan string, sentinelSignaller) {
   229  	var ch byte
   230  	var state string
   231  	var quote bool
   232  	var lastnewline bool
   233  
   234  	eot := make(sentinelSignaller)
   235  
   236  	out := make(chan string)
   237  	go func(out chan string) {
   238  		for stillReading := true; stillReading; {
   239  			select {
   240  			case <-eof:
   241  				stillReading = false
   242  
   243  			case ch = <-in:
   244  				if quote {
   245  					if ch == '"' {
   246  						out <- state + string(ch)
   247  						state, quote = "", false
   248  						continue
   249  					}
   250  					state += string(ch)
   251  					continue
   252  				}
   253  
   254  				switch ch {
   255  				case '"':
   256  					quote = true
   257  					state += string(ch)
   258  					continue
   259  
   260  				case '\r':
   261  					fallthrough
   262  				case '\t':
   263  					fallthrough
   264  				case ' ':
   265  					if len(state) == 0 {
   266  						continue
   267  					}
   268  					out <- state
   269  					state = ""
   270  
   271  				case '\n':
   272  					if lastnewline {
   273  						continue
   274  					}
   275  					if len(state) > 0 {
   276  						out <- state
   277  					}
   278  					out <- string(ch)
   279  					state = ""
   280  					lastnewline = true
   281  					continue
   282  
   283  				case '.':
   284  					fallthrough
   285  				case '=':
   286  					if len(state) > 0 {
   287  						out <- state
   288  					}
   289  					out <- string(ch)
   290  					state = ""
   291  
   292  				default:
   293  					state += string(ch)
   294  				}
   295  				lastnewline = false
   296  			}
   297  		}
   298  		if len(state) > 0 {
   299  			out <- state
   300  		}
   301  		close(eot)
   302  	}(out)
   303  	return out, eot
   304  }
   305  
   306  func parseNetworkMapConfig(eof sentinelSignaller, in chan string) (NetworkMap, error) {
   307  	var unsorted map[string]map[string]string
   308  	var state []string
   309  
   310  	addResult := func(network string, attribute string, value string) error {
   311  		_, ok := unsorted[network]
   312  		if !ok {
   313  			unsorted[network] = make(map[string]string)
   314  		}
   315  
   316  		val, err := strconv.Unquote(value)
   317  		if err != nil {
   318  			return err
   319  		}
   320  
   321  		current := unsorted[network]
   322  		current[attribute] = val
   323  		return nil
   324  	}
   325  
   326  	stillReading := true
   327  	for unsorted = make(map[string]map[string]string); stillReading; {
   328  		select {
   329  		case <-eof:
   330  			if len(state) == 3 {
   331  				err := addResult(state[0], state[1], state[2])
   332  				if err != nil {
   333  					return nil, err
   334  				}
   335  			}
   336  			stillReading = false
   337  		case tk := <-in:
   338  			switch tk {
   339  			case ".":
   340  				if len(state) != 1 {
   341  					return nil, fmt.Errorf("Missing network index")
   342  				}
   343  			case "=":
   344  				if len(state) != 2 {
   345  					return nil, fmt.Errorf("Assignment to empty attribute")
   346  				}
   347  			case "\n":
   348  				if len(state) == 0 {
   349  					continue
   350  				}
   351  				if len(state) != 3 {
   352  					return nil, fmt.Errorf("Invalid attribute assignment : %v", state)
   353  				}
   354  				err := addResult(state[0], state[1], state[2])
   355  				if err != nil {
   356  					return nil, err
   357  				}
   358  				state = make([]string, 0)
   359  			default:
   360  				state = append(state, tk)
   361  			}
   362  		}
   363  	}
   364  	result := make([]map[string]string, 0)
   365  	var keys []string
   366  	for k := range unsorted {
   367  		keys = append(keys, k)
   368  	}
   369  	sort.Strings(keys)
   370  	for _, k := range keys {
   371  		result = append(result, unsorted[k])
   372  	}
   373  	return result, nil
   374  }
   375  
   376  /** higher-level parsing */
   377  /// parameters
   378  type pParameter interface {
   379  	repr() string
   380  }
   381  
   382  type pParameterInclude struct {
   383  	filename string
   384  }
   385  
   386  func (e pParameterInclude) repr() string { return fmt.Sprintf("include-file:filename=%s", e.filename) }
   387  
   388  type pParameterOption struct {
   389  	name  string
   390  	value string
   391  }
   392  
   393  func (e pParameterOption) repr() string { return fmt.Sprintf("option:%s=%s", e.name, e.value) }
   394  
   395  // allow some-kind-of-something
   396  type pParameterGrant struct {
   397  	verb      string // allow,deny,ignore
   398  	attribute string
   399  }
   400  
   401  func (e pParameterGrant) repr() string { return fmt.Sprintf("grant:%s,%s", e.verb, e.attribute) }
   402  
   403  type pParameterAddress4 []string
   404  
   405  func (e pParameterAddress4) repr() string {
   406  	return fmt.Sprintf("fixed-address4:%s", strings.Join(e, ","))
   407  }
   408  
   409  type pParameterAddress6 []string
   410  
   411  func (e pParameterAddress6) repr() string {
   412  	return fmt.Sprintf("fixed-address6:%s", strings.Join(e, ","))
   413  }
   414  
   415  // hardware address 00:00:00:00:00:00
   416  type pParameterHardware struct {
   417  	class   string
   418  	address []byte
   419  }
   420  
   421  func (e pParameterHardware) repr() string {
   422  	res := make([]string, 0)
   423  	for _, v := range e.address {
   424  		res = append(res, fmt.Sprintf("%02x", v))
   425  	}
   426  	return fmt.Sprintf("hardware-address:%s[%s]", e.class, strings.Join(res, ":"))
   427  }
   428  
   429  type pParameterBoolean struct {
   430  	parameter string
   431  	truancy   bool
   432  }
   433  
   434  func (e pParameterBoolean) repr() string { return fmt.Sprintf("boolean:%s=%v", e.parameter, e.truancy) }
   435  
   436  type pParameterClientMatch struct {
   437  	name string
   438  	data string
   439  }
   440  
   441  func (e pParameterClientMatch) repr() string { return fmt.Sprintf("match-client:%s=%s", e.name, e.data) }
   442  
   443  // range 127.0.0.1 127.0.0.255
   444  type pParameterRange4 struct {
   445  	min net.IP
   446  	max net.IP
   447  }
   448  
   449  func (e pParameterRange4) repr() string {
   450  	return fmt.Sprintf("range4:%s-%s", e.min.String(), e.max.String())
   451  }
   452  
   453  type pParameterRange6 struct {
   454  	min net.IP
   455  	max net.IP
   456  }
   457  
   458  func (e pParameterRange6) repr() string {
   459  	return fmt.Sprintf("range6:%s-%s", e.min.String(), e.max.String())
   460  }
   461  
   462  type pParameterPrefix6 struct {
   463  	min  net.IP
   464  	max  net.IP
   465  	bits int
   466  }
   467  
   468  func (e pParameterPrefix6) repr() string {
   469  	return fmt.Sprintf("prefix6:/%d:%s-%s", e.bits, e.min.String(), e.max.String())
   470  }
   471  
   472  // some-kind-of-parameter 1024
   473  type pParameterOther struct {
   474  	parameter string
   475  	value     string
   476  }
   477  
   478  func (e pParameterOther) repr() string { return fmt.Sprintf("parameter:%s=%s", e.parameter, e.value) }
   479  
   480  type pParameterExpression struct {
   481  	parameter  string
   482  	expression string
   483  }
   484  
   485  func (e pParameterExpression) repr() string {
   486  	return fmt.Sprintf("parameter-expression:%s=\"%s\"", e.parameter, e.expression)
   487  }
   488  
   489  type pDeclarationIdentifier interface {
   490  	repr() string
   491  }
   492  
   493  type pDeclaration struct {
   494  	id           pDeclarationIdentifier
   495  	parent       *pDeclaration
   496  	parameters   []pParameter
   497  	declarations []pDeclaration
   498  }
   499  
   500  func (e *pDeclaration) short() string {
   501  	return e.id.repr()
   502  }
   503  
   504  func (e *pDeclaration) repr() string {
   505  	res := e.short()
   506  
   507  	var parameters []string
   508  	for _, v := range e.parameters {
   509  		parameters = append(parameters, v.repr())
   510  	}
   511  
   512  	var groups []string
   513  	for _, v := range e.declarations {
   514  		groups = append(groups, fmt.Sprintf("-> %s", v.short()))
   515  	}
   516  
   517  	if e.parent != nil {
   518  		res = fmt.Sprintf("%s parent:%s", res, e.parent.short())
   519  	}
   520  	return fmt.Sprintf("%s\n%s\n%s\n", res, strings.Join(parameters, "\n"), strings.Join(groups, "\n"))
   521  }
   522  
   523  type pDeclarationGlobal struct{}
   524  
   525  func (e pDeclarationGlobal) repr() string { return fmt.Sprintf("{global}") }
   526  
   527  type pDeclarationShared struct{ name string }
   528  
   529  func (e pDeclarationShared) repr() string { return fmt.Sprintf("{shared-network %s}", e.name) }
   530  
   531  type pDeclarationSubnet4 struct{ net.IPNet }
   532  
   533  func (e pDeclarationSubnet4) repr() string { return fmt.Sprintf("{subnet4 %s}", e.String()) }
   534  
   535  type pDeclarationSubnet6 struct{ net.IPNet }
   536  
   537  func (e pDeclarationSubnet6) repr() string { return fmt.Sprintf("{subnet6 %s}", e.String()) }
   538  
   539  type pDeclarationHost struct{ name string }
   540  
   541  func (e pDeclarationHost) repr() string { return fmt.Sprintf("{host name:%s}", e.name) }
   542  
   543  type pDeclarationPool struct{}
   544  
   545  func (e pDeclarationPool) repr() string { return fmt.Sprintf("{pool}") }
   546  
   547  type pDeclarationGroup struct{}
   548  
   549  func (e pDeclarationGroup) repr() string { return fmt.Sprintf("{group}") }
   550  
   551  type pDeclarationClass struct{ name string }
   552  
   553  func (e pDeclarationClass) repr() string { return fmt.Sprintf("{class}") }
   554  
   555  /** parsers */
   556  func parseParameter(val tkParameter) (pParameter, error) {
   557  	switch val.name {
   558  	case "include":
   559  		if len(val.operand) != 2 {
   560  			return nil, fmt.Errorf("Invalid number of parameters for pParameterInclude : %v", val.operand)
   561  		}
   562  		name := val.operand[0]
   563  		return pParameterInclude{filename: name}, nil
   564  
   565  	case "option":
   566  		if len(val.operand) != 2 {
   567  			return nil, fmt.Errorf("Invalid number of parameters for pParameterOption : %v", val.operand)
   568  		}
   569  		name, value := val.operand[0], val.operand[1]
   570  		return pParameterOption{name: name, value: value}, nil
   571  
   572  	case "allow":
   573  		fallthrough
   574  	case "deny":
   575  		fallthrough
   576  	case "ignore":
   577  		if len(val.operand) < 1 {
   578  			return nil, fmt.Errorf("Invalid number of parameters for pParameterGrant : %v", val.operand)
   579  		}
   580  		attribute := strings.Join(val.operand, " ")
   581  		return pParameterGrant{verb: strings.ToLower(val.name), attribute: attribute}, nil
   582  
   583  	case "range":
   584  		if len(val.operand) < 1 {
   585  			return nil, fmt.Errorf("Invalid number of parameters for pParameterRange4 : %v", val.operand)
   586  		}
   587  		idxAddress := map[bool]int{true: 1, false: 0}[strings.ToLower(val.operand[0]) == "bootp"]
   588  		if len(val.operand) > 2+idxAddress {
   589  			return nil, fmt.Errorf("Invalid number of parameters for pParameterRange : %v", val.operand)
   590  		}
   591  		if idxAddress+1 > len(val.operand) {
   592  			res := net.ParseIP(val.operand[idxAddress])
   593  			return pParameterRange4{min: res, max: res}, nil
   594  		}
   595  		addr1 := net.ParseIP(val.operand[idxAddress])
   596  		addr2 := net.ParseIP(val.operand[idxAddress+1])
   597  		return pParameterRange4{min: addr1, max: addr2}, nil
   598  
   599  	case "range6":
   600  		if len(val.operand) == 1 {
   601  			address := val.operand[0]
   602  			if strings.Contains(address, "/") {
   603  				cidr := strings.SplitN(address, "/", 2)
   604  				if len(cidr) != 2 {
   605  					return nil, fmt.Errorf("Unknown ipv6 format : %v", address)
   606  				}
   607  				address := net.ParseIP(cidr[0])
   608  				bits, err := strconv.Atoi(cidr[1])
   609  				if err != nil {
   610  					return nil, err
   611  				}
   612  				mask := net.CIDRMask(bits, net.IPv6len*8)
   613  
   614  				// figure out the network address
   615  				network := address.Mask(mask)
   616  
   617  				// make a broadcast address
   618  				broadcast := network
   619  				networkSize, totalSize := mask.Size()
   620  				hostSize := totalSize - networkSize
   621  				for i := networkSize / 8; i < totalSize/8; i++ {
   622  					broadcast[i] = byte(0xff)
   623  				}
   624  				octetIndex := network[networkSize/8]
   625  				bitsLeft := (uint32)(hostSize % 8)
   626  				broadcast[octetIndex] = network[octetIndex] | ((1 << bitsLeft) - 1)
   627  
   628  				// FIXME: check that the broadcast address was made correctly
   629  				return pParameterRange6{min: network, max: broadcast}, nil
   630  			}
   631  			res := net.ParseIP(address)
   632  			return pParameterRange6{min: res, max: res}, nil
   633  		}
   634  		if len(val.operand) == 2 {
   635  			addr := net.ParseIP(val.operand[0])
   636  			if strings.ToLower(val.operand[1]) == "temporary" {
   637  				return pParameterRange6{min: addr, max: addr}, nil
   638  			}
   639  			other := net.ParseIP(val.operand[1])
   640  			return pParameterRange6{min: addr, max: other}, nil
   641  		}
   642  		return nil, fmt.Errorf("Invalid number of parameters for pParameterRange6 : %v", val.operand)
   643  
   644  	case "prefix6":
   645  		if len(val.operand) != 3 {
   646  			return nil, fmt.Errorf("Invalid number of parameters for pParameterRange6 : %v", val.operand)
   647  		}
   648  		bits, err := strconv.Atoi(val.operand[2])
   649  		if err != nil {
   650  			return nil, fmt.Errorf("Invalid bits for pParameterPrefix6 : %v", val.operand[2])
   651  		}
   652  		minaddr := net.ParseIP(val.operand[0])
   653  		maxaddr := net.ParseIP(val.operand[1])
   654  		return pParameterPrefix6{min: minaddr, max: maxaddr, bits: bits}, nil
   655  
   656  	case "hardware":
   657  		if len(val.operand) != 2 {
   658  			return nil, fmt.Errorf("Invalid number of parameters for pParameterHardware : %v", val.operand)
   659  		}
   660  		class := val.operand[0]
   661  		octets := strings.Split(val.operand[1], ":")
   662  		address := make([]byte, 0)
   663  		for _, v := range octets {
   664  			b, err := strconv.ParseInt(v, 16, 0)
   665  			if err != nil {
   666  				return nil, err
   667  			}
   668  			address = append(address, byte(b))
   669  		}
   670  		return pParameterHardware{class: class, address: address}, nil
   671  
   672  	case "fixed-address":
   673  		ip4addrs := make(pParameterAddress4, len(val.operand))
   674  		copy(ip4addrs, val.operand)
   675  		return ip4addrs, nil
   676  
   677  	case "fixed-address6":
   678  		ip6addrs := make(pParameterAddress6, len(val.operand))
   679  		copy(ip6addrs, val.operand)
   680  		return ip6addrs, nil
   681  
   682  	case "host-identifier":
   683  		if len(val.operand) != 3 {
   684  			return nil, fmt.Errorf("Invalid number of parameters for pParameterClientMatch : %v", val.operand)
   685  		}
   686  		if val.operand[0] != "option" {
   687  			return nil, fmt.Errorf("Invalid match parameter : %v", val.operand[0])
   688  		}
   689  		optionName := val.operand[1]
   690  		optionData := val.operand[2]
   691  		return pParameterClientMatch{name: optionName, data: optionData}, nil
   692  
   693  	default:
   694  		length := len(val.operand)
   695  		if length < 1 {
   696  			return pParameterBoolean{parameter: val.name, truancy: true}, nil
   697  		} else if length > 1 {
   698  			if val.operand[0] == "=" {
   699  				return pParameterExpression{parameter: val.name, expression: strings.Join(val.operand[1:], "")}, nil
   700  			}
   701  		}
   702  		if length != 1 {
   703  			return nil, fmt.Errorf("Invalid number of parameters for pParameterOther : %v", val.operand)
   704  		}
   705  		if strings.ToLower(val.name) == "not" {
   706  			return pParameterBoolean{parameter: val.operand[0], truancy: false}, nil
   707  		}
   708  		return pParameterOther{parameter: val.name, value: val.operand[0]}, nil
   709  	}
   710  }
   711  
   712  func parseTokenGroup(val tkGroup) (*pDeclaration, error) {
   713  	params := val.id.operand
   714  	switch val.id.name {
   715  	case "group":
   716  		return &pDeclaration{id: pDeclarationGroup{}}, nil
   717  
   718  	case "pool":
   719  		return &pDeclaration{id: pDeclarationPool{}}, nil
   720  
   721  	case "host":
   722  		if len(params) == 1 {
   723  			return &pDeclaration{id: pDeclarationHost{name: params[0]}}, nil
   724  		}
   725  
   726  	case "subnet":
   727  		if len(params) == 3 && strings.ToLower(params[1]) == "netmask" {
   728  			addr := make([]byte, 4)
   729  			for i, v := range strings.SplitN(params[2], ".", 4) {
   730  				res, err := strconv.ParseInt(v, 10, 0)
   731  				if err != nil {
   732  					return nil, err
   733  				}
   734  				addr[i] = byte(res)
   735  			}
   736  			oc1, oc2, oc3, oc4 := addr[0], addr[1], addr[2], addr[3]
   737  			if subnet, mask := net.ParseIP(params[0]), net.IPv4Mask(oc1, oc2, oc3, oc4); subnet != nil && mask != nil {
   738  				return &pDeclaration{id: pDeclarationSubnet4{net.IPNet{IP: subnet, Mask: mask}}}, nil
   739  			}
   740  		}
   741  	case "subnet6":
   742  		if len(params) == 1 {
   743  			ip6 := strings.SplitN(params[0], "/", 2)
   744  			if len(ip6) == 2 && strings.Contains(ip6[0], ":") {
   745  				address := net.ParseIP(ip6[0])
   746  				prefix, err := strconv.Atoi(ip6[1])
   747  				if err != nil {
   748  					return nil, err
   749  				}
   750  				return &pDeclaration{id: pDeclarationSubnet6{net.IPNet{IP: address, Mask: net.CIDRMask(prefix, net.IPv6len*8)}}}, nil
   751  			}
   752  		}
   753  	case "shared-network":
   754  		if len(params) == 1 {
   755  			return &pDeclaration{id: pDeclarationShared{name: params[0]}}, nil
   756  		}
   757  	case "":
   758  		return &pDeclaration{id: pDeclarationGlobal{}}, nil
   759  	}
   760  	return nil, fmt.Errorf("Invalid pDeclaration : %v : %v", val.id.name, params)
   761  }
   762  
   763  func flattenDhcpConfig(root tkGroup) (*pDeclaration, error) {
   764  	var result *pDeclaration
   765  	result, err := parseTokenGroup(root)
   766  	if err != nil {
   767  		return nil, err
   768  	}
   769  
   770  	for _, p := range root.params {
   771  		param, err := parseParameter(p)
   772  		if err != nil {
   773  			return nil, err
   774  		}
   775  		result.parameters = append(result.parameters, param)
   776  	}
   777  	for _, p := range root.groups {
   778  		group, err := flattenDhcpConfig(*p)
   779  		if err != nil {
   780  			return nil, err
   781  		}
   782  		group.parent = result
   783  		result.declarations = append(result.declarations, *group)
   784  	}
   785  	return result, nil
   786  }
   787  
   788  /** reduce the tree into the things that we care about */
   789  type grant uint
   790  
   791  const (
   792  	ALLOW  grant = iota
   793  	IGNORE grant = iota
   794  	DENY   grant = iota
   795  )
   796  
   797  type configDeclaration struct {
   798  	id         []pDeclarationIdentifier
   799  	composites []pDeclaration
   800  
   801  	address []pParameter
   802  
   803  	options     map[string]string
   804  	grants      map[string]grant
   805  	attributes  map[string]bool
   806  	parameters  map[string]string
   807  	expressions map[string]string
   808  
   809  	hostid []pParameterClientMatch
   810  }
   811  
   812  func createDeclaration(node pDeclaration) configDeclaration {
   813  	var hierarchy []pDeclaration
   814  
   815  	for n := &node; n != nil; n = n.parent {
   816  		hierarchy = append(hierarchy, *n)
   817  	}
   818  
   819  	var result configDeclaration
   820  	result.address = make([]pParameter, 0)
   821  
   822  	result.options = make(map[string]string)
   823  	result.grants = make(map[string]grant)
   824  	result.attributes = make(map[string]bool)
   825  	result.parameters = make(map[string]string)
   826  	result.expressions = make(map[string]string)
   827  
   828  	result.hostid = make([]pParameterClientMatch, 0)
   829  
   830  	// walk from globals to pDeclaration collecting all parameters
   831  	for i := len(hierarchy) - 1; i >= 0; i-- {
   832  		result.composites = append(result.composites, hierarchy[(len(hierarchy)-1)-i])
   833  		result.id = append(result.id, hierarchy[(len(hierarchy)-1)-i].id)
   834  
   835  		// update configDeclaration parameters
   836  		for _, p := range hierarchy[i].parameters {
   837  			switch p.(type) {
   838  			case pParameterOption:
   839  				result.options[p.(pParameterOption).name] = p.(pParameterOption).value
   840  			case pParameterGrant:
   841  				Grant := map[string]grant{"ignore": IGNORE, "allow": ALLOW, "deny": DENY}
   842  				result.grants[p.(pParameterGrant).attribute] = Grant[p.(pParameterGrant).verb]
   843  			case pParameterBoolean:
   844  				result.attributes[p.(pParameterBoolean).parameter] = p.(pParameterBoolean).truancy
   845  			case pParameterClientMatch:
   846  				result.hostid = append(result.hostid, p.(pParameterClientMatch))
   847  			case pParameterExpression:
   848  				result.expressions[p.(pParameterExpression).parameter] = p.(pParameterExpression).expression
   849  			case pParameterOther:
   850  				result.parameters[p.(pParameterOther).parameter] = p.(pParameterOther).value
   851  			default:
   852  				result.address = append(result.address, p)
   853  			}
   854  		}
   855  	}
   856  	return result
   857  }
   858  
   859  func (e *configDeclaration) repr() string {
   860  	var result []string
   861  
   862  	var res []string
   863  
   864  	res = make([]string, 0)
   865  	for _, v := range e.id {
   866  		res = append(res, v.repr())
   867  	}
   868  	result = append(result, strings.Join(res, ","))
   869  
   870  	if len(e.address) > 0 {
   871  		res = make([]string, 0)
   872  		for _, v := range e.address {
   873  			res = append(res, v.repr())
   874  		}
   875  		result = append(result, fmt.Sprintf("address : %v", strings.Join(res, ",")))
   876  	}
   877  
   878  	if len(e.options) > 0 {
   879  		result = append(result, fmt.Sprintf("options : %v", e.options))
   880  	}
   881  	if len(e.grants) > 0 {
   882  		result = append(result, fmt.Sprintf("grants : %v", e.grants))
   883  	}
   884  	if len(e.attributes) > 0 {
   885  		result = append(result, fmt.Sprintf("attributes : %v", e.attributes))
   886  	}
   887  	if len(e.parameters) > 0 {
   888  		result = append(result, fmt.Sprintf("parameters : %v", e.parameters))
   889  	}
   890  	if len(e.expressions) > 0 {
   891  		result = append(result, fmt.Sprintf("parameter-expressions : %v", e.expressions))
   892  	}
   893  
   894  	if len(e.hostid) > 0 {
   895  		res = make([]string, 0)
   896  		for _, v := range e.hostid {
   897  			res = append(res, v.repr())
   898  		}
   899  		result = append(result, fmt.Sprintf("hostid : %v", strings.Join(res, " ")))
   900  	}
   901  	return strings.Join(result, "\n") + "\n"
   902  }
   903  
   904  func (e *configDeclaration) IP4() (net.IP, error) {
   905  	var result []string
   906  	for _, entry := range e.address {
   907  		switch entry.(type) {
   908  		case pParameterAddress4:
   909  			for _, s := range entry.(pParameterAddress4) {
   910  				result = append(result, s)
   911  			}
   912  		}
   913  	}
   914  	if len(result) > 1 {
   915  		return nil, fmt.Errorf("More than one address4 returned : %v", result)
   916  	} else if len(result) == 0 {
   917  		return nil, fmt.Errorf("No IP4 addresses found")
   918  	}
   919  
   920  	if res := net.ParseIP(result[0]); res != nil {
   921  		return res, nil
   922  	}
   923  	res, err := net.ResolveIPAddr("ip4", result[0])
   924  	if err != nil {
   925  		return nil, err
   926  	}
   927  	return res.IP, nil
   928  }
   929  func (e *configDeclaration) IP6() (net.IP, error) {
   930  	var result []string
   931  	for _, entry := range e.address {
   932  		switch entry.(type) {
   933  		case pParameterAddress6:
   934  			for _, s := range entry.(pParameterAddress6) {
   935  				result = append(result, s)
   936  			}
   937  		}
   938  	}
   939  	if len(result) > 1 {
   940  		return nil, fmt.Errorf("More than one address6 returned : %v", result)
   941  	} else if len(result) == 0 {
   942  		return nil, fmt.Errorf("No IP6 addresses found")
   943  	}
   944  
   945  	if res := net.ParseIP(result[0]); res != nil {
   946  		return res, nil
   947  	}
   948  	res, err := net.ResolveIPAddr("ip6", result[0])
   949  	if err != nil {
   950  		return nil, err
   951  	}
   952  	return res.IP, nil
   953  }
   954  func (e *configDeclaration) Hardware() (net.HardwareAddr, error) {
   955  	var result []pParameterHardware
   956  	for _, addr := range e.address {
   957  		switch addr.(type) {
   958  		case pParameterHardware:
   959  			result = append(result, addr.(pParameterHardware))
   960  		}
   961  	}
   962  	if len(result) > 0 {
   963  		return nil, fmt.Errorf("More than one hardware address returned : %v", result)
   964  	}
   965  	res := make(net.HardwareAddr, 0)
   966  	for _, by := range result[0].address {
   967  		res = append(res, by)
   968  	}
   969  	return res, nil
   970  }
   971  
   972  /*** Dhcp Configuration */
   973  type DhcpConfiguration []configDeclaration
   974  
   975  func ReadDhcpConfiguration(fd *os.File) (DhcpConfiguration, error) {
   976  	fromfile, eof := consumeFile(fd)
   977  	uncommented, eoc := uncomment(eof, fromfile)
   978  	tokenized, eot := tokenizeDhcpConfig(eoc, uncommented)
   979  	parsetree, err := parseDhcpConfig(eot, tokenized)
   980  	if err != nil {
   981  		return nil, err
   982  	}
   983  
   984  	global, err := flattenDhcpConfig(parsetree)
   985  	if err != nil {
   986  		return nil, err
   987  	}
   988  
   989  	var walkDeclarations func(root pDeclaration, out chan *configDeclaration)
   990  	walkDeclarations = func(root pDeclaration, out chan *configDeclaration) {
   991  		res := createDeclaration(root)
   992  		out <- &res
   993  		for _, p := range root.declarations {
   994  			walkDeclarations(p, out)
   995  		}
   996  	}
   997  
   998  	each := make(chan *configDeclaration)
   999  	go func(out chan *configDeclaration) {
  1000  		walkDeclarations(*global, out)
  1001  		out <- nil
  1002  	}(each)
  1003  
  1004  	var result DhcpConfiguration
  1005  	for decl := <-each; decl != nil; decl = <-each {
  1006  		result = append(result, *decl)
  1007  	}
  1008  	return result, nil
  1009  }
  1010  
  1011  func (e *DhcpConfiguration) Global() configDeclaration {
  1012  	result := (*e)[0]
  1013  	if len(result.id) != 1 {
  1014  		panic(fmt.Errorf("Something that can't happen happened"))
  1015  	}
  1016  	return result
  1017  }
  1018  
  1019  func (e *DhcpConfiguration) SubnetByAddress(address net.IP) (configDeclaration, error) {
  1020  	var result []configDeclaration
  1021  	for _, entry := range *e {
  1022  		switch entry.id[0].(type) {
  1023  		case pDeclarationSubnet4:
  1024  			id := entry.id[0].(pDeclarationSubnet4)
  1025  			if id.Contains(address) {
  1026  				result = append(result, entry)
  1027  			}
  1028  		case pDeclarationSubnet6:
  1029  			id := entry.id[0].(pDeclarationSubnet6)
  1030  			if id.Contains(address) {
  1031  				result = append(result, entry)
  1032  			}
  1033  		}
  1034  	}
  1035  	if len(result) == 0 {
  1036  		return configDeclaration{}, fmt.Errorf("No network declarations containing %s found", address.String())
  1037  	}
  1038  	if len(result) > 1 {
  1039  		return configDeclaration{}, fmt.Errorf("More than 1 network declaration found : %v", result)
  1040  	}
  1041  	return result[0], nil
  1042  }
  1043  
  1044  func (e *DhcpConfiguration) HostByName(host string) (configDeclaration, error) {
  1045  	var result []configDeclaration
  1046  	for _, entry := range *e {
  1047  		switch entry.id[0].(type) {
  1048  		case pDeclarationHost:
  1049  			id := entry.id[0].(pDeclarationHost)
  1050  			if strings.ToLower(id.name) == strings.ToLower(host) {
  1051  				result = append(result, entry)
  1052  			}
  1053  		}
  1054  	}
  1055  	if len(result) == 0 {
  1056  		return configDeclaration{}, fmt.Errorf("No host declarations containing %s found", host)
  1057  	}
  1058  	if len(result) > 1 {
  1059  		return configDeclaration{}, fmt.Errorf("More than 1 host declaration found : %v", result)
  1060  	}
  1061  	return result[0], nil
  1062  }
  1063  
  1064  /*** Network Map */
  1065  type NetworkMap []map[string]string
  1066  
  1067  type NetworkNameMapper interface {
  1068  	NameIntoDevices(string) ([]string, error)
  1069  	DeviceIntoName(string) (string, error)
  1070  }
  1071  
  1072  func ReadNetworkMap(fd *os.File) (NetworkMap, error) {
  1073  
  1074  	fromfile, eof := consumeFile(fd)
  1075  	uncommented, eoc := uncomment(eof, fromfile)
  1076  	tokenized, eot := tokenizeNetworkMapConfig(eoc, uncommented)
  1077  
  1078  	result, err := parseNetworkMapConfig(eot, tokenized)
  1079  	if err != nil {
  1080  		return nil, err
  1081  	}
  1082  	return result, nil
  1083  }
  1084  
  1085  func (e NetworkMap) NameIntoDevices(name string) ([]string, error) {
  1086  	var devices []string
  1087  	for _, val := range e {
  1088  		if strings.ToLower(val["name"]) == strings.ToLower(name) {
  1089  			devices = append(devices, val["device"])
  1090  		}
  1091  	}
  1092  	if len(devices) > 0 {
  1093  		return devices, nil
  1094  	}
  1095  	return make([]string, 0), fmt.Errorf("Network name not found : %v", name)
  1096  }
  1097  func (e NetworkMap) DeviceIntoName(device string) (string, error) {
  1098  	for _, val := range e {
  1099  		if strings.ToLower(val["device"]) == strings.ToLower(device) {
  1100  			return val["name"], nil
  1101  		}
  1102  	}
  1103  	return "", fmt.Errorf("Device name not found : %v", device)
  1104  }
  1105  func (e *NetworkMap) repr() string {
  1106  	var result []string
  1107  	for idx, val := range *e {
  1108  		result = append(result, fmt.Sprintf("network%d.name = \"%s\"", idx, val["name"]))
  1109  		result = append(result, fmt.Sprintf("network%d.device = \"%s\"", idx, val["device"]))
  1110  	}
  1111  	return strings.Join(result, "\n")
  1112  }
  1113  
  1114  /*** parser for VMware Fusion's networking file */
  1115  func tokenizeNetworkingConfig(eof sentinelSignaller, in chan byte) (chan string, sentinelSignaller) {
  1116  	var ch byte
  1117  	var state string
  1118  	var repeat_newline bool
  1119  
  1120  	eot := make(sentinelSignaller)
  1121  
  1122  	out := make(chan string)
  1123  	go func(out chan string) {
  1124  		for reading := true; reading; {
  1125  			select {
  1126  			case <-eof:
  1127  				reading = false
  1128  
  1129  			case ch = <-in:
  1130  				switch ch {
  1131  				case '\r':
  1132  					fallthrough
  1133  				case '\t':
  1134  					fallthrough
  1135  				case ' ':
  1136  					if len(state) == 0 {
  1137  						continue
  1138  					}
  1139  					out <- state
  1140  					state = ""
  1141  				case '\n':
  1142  					if repeat_newline {
  1143  						continue
  1144  					}
  1145  					if len(state) > 0 {
  1146  						out <- state
  1147  					}
  1148  					out <- string(ch)
  1149  					state = ""
  1150  					repeat_newline = true
  1151  					continue
  1152  				default:
  1153  					state += string(ch)
  1154  				}
  1155  				repeat_newline = false
  1156  			}
  1157  		}
  1158  		if len(state) > 0 {
  1159  			out <- state
  1160  		}
  1161  		close(eot)
  1162  	}(out)
  1163  	return out, eot
  1164  }
  1165  
  1166  func splitNetworkingConfig(eof sentinelSignaller, in chan string) (chan []string, sentinelSignaller) {
  1167  	var out chan []string
  1168  
  1169  	eos := make(sentinelSignaller)
  1170  
  1171  	out = make(chan []string)
  1172  	go func(out chan []string) {
  1173  		row := make([]string, 0)
  1174  		for reading := true; reading; {
  1175  			select {
  1176  			case <-eof:
  1177  				reading = false
  1178  
  1179  			case tk := <-in:
  1180  				switch tk {
  1181  				case "\n":
  1182  					if len(row) > 0 {
  1183  						out <- row
  1184  					}
  1185  					row = make([]string, 0)
  1186  				default:
  1187  					row = append(row, tk)
  1188  				}
  1189  			}
  1190  		}
  1191  		if len(row) > 0 {
  1192  			out <- row
  1193  		}
  1194  		close(eos)
  1195  	}(out)
  1196  	return out, eos
  1197  }
  1198  
  1199  /// All token types in networking file.
  1200  // VERSION token
  1201  type networkingVERSION struct {
  1202  	value string
  1203  }
  1204  
  1205  func networkingReadVersion(row []string) (*networkingVERSION, error) {
  1206  	if len(row) != 1 {
  1207  		return nil, fmt.Errorf("Unexpected format for VERSION entry : %v", row)
  1208  	}
  1209  	res := &networkingVERSION{value: row[0]}
  1210  	if !res.Valid() {
  1211  		return nil, fmt.Errorf("Unexpected format for VERSION entry : %v", row)
  1212  	}
  1213  	return res, nil
  1214  }
  1215  
  1216  func (s networkingVERSION) Repr() string {
  1217  	if !s.Valid() {
  1218  		return fmt.Sprintf("VERSION{INVALID=\"%v\"}", s.value)
  1219  	}
  1220  	return fmt.Sprintf("VERSION{%f}", s.Number())
  1221  }
  1222  
  1223  func (s networkingVERSION) Valid() bool {
  1224  	tokens := strings.SplitN(s.value, "=", 2)
  1225  	if len(tokens) != 2 || tokens[0] != "VERSION" {
  1226  		return false
  1227  	}
  1228  
  1229  	tokens = strings.Split(tokens[1], ",")
  1230  	if len(tokens) != 2 {
  1231  		return false
  1232  	}
  1233  
  1234  	for _, t := range tokens {
  1235  		_, err := strconv.ParseUint(t, 10, 64)
  1236  		if err != nil {
  1237  			return false
  1238  		}
  1239  	}
  1240  	return true
  1241  }
  1242  
  1243  func (s networkingVERSION) Number() float64 {
  1244  	var result float64
  1245  	tokens := strings.SplitN(s.value, "=", 2)
  1246  	tokens = strings.Split(tokens[1], ",")
  1247  
  1248  	integer, err := strconv.ParseUint(tokens[0], 10, 64)
  1249  	if err != nil {
  1250  		integer = 0
  1251  	}
  1252  	result = float64(integer)
  1253  
  1254  	mantissa, err := strconv.ParseUint(tokens[1], 10, 64)
  1255  	if err != nil {
  1256  		return result
  1257  	}
  1258  	denomination := math.Pow(10.0, float64(len(tokens[1])))
  1259  	return result + (float64(mantissa) / denomination)
  1260  }
  1261  
  1262  // VNET_X token
  1263  type networkingVNET struct {
  1264  	value string
  1265  }
  1266  
  1267  func (s networkingVNET) Valid() bool {
  1268  	if strings.ToUpper(s.value) != s.value {
  1269  		return false
  1270  	}
  1271  	tokens := strings.SplitN(s.value, "_", 3)
  1272  	if len(tokens) != 3 || tokens[0] != "VNET" {
  1273  		return false
  1274  	}
  1275  	_, err := strconv.ParseUint(tokens[1], 10, 64)
  1276  	if err != nil {
  1277  		return false
  1278  	}
  1279  	return true
  1280  }
  1281  
  1282  func (s networkingVNET) Number() int {
  1283  	tokens := strings.SplitN(s.value, "_", 3)
  1284  	res, err := strconv.Atoi(tokens[1])
  1285  	if err != nil {
  1286  		return ^int(0)
  1287  	}
  1288  	return res
  1289  }
  1290  
  1291  func (s networkingVNET) Option() string {
  1292  	tokens := strings.SplitN(s.value, "_", 3)
  1293  	if len(tokens) == 3 {
  1294  		return tokens[2]
  1295  	}
  1296  	return ""
  1297  }
  1298  
  1299  func (s networkingVNET) Repr() string {
  1300  	if !s.Valid() {
  1301  		tokens := strings.SplitN(s.value, "_", 3)
  1302  		return fmt.Sprintf("VNET{INVALID=%v}", tokens)
  1303  	}
  1304  	return fmt.Sprintf("VNET{%d} %s", s.Number(), s.Option())
  1305  }
  1306  
  1307  // Interface name
  1308  type networkingInterface struct {
  1309  	name string
  1310  }
  1311  
  1312  func (s networkingInterface) Interface() (*net.Interface, error) {
  1313  	return net.InterfaceByName(s.name)
  1314  }
  1315  
  1316  // networking command entry types
  1317  type networkingCommandEntry_answer struct {
  1318  	vnet  networkingVNET
  1319  	value string
  1320  }
  1321  type networkingCommandEntry_remove_answer struct {
  1322  	vnet networkingVNET
  1323  }
  1324  type networkingCommandEntry_add_nat_portfwd struct {
  1325  	vnet        int
  1326  	protocol    string
  1327  	port        int
  1328  	target_host net.IP
  1329  	target_port int
  1330  }
  1331  type networkingCommandEntry_remove_nat_portfwd struct {
  1332  	vnet     int
  1333  	protocol string
  1334  	port     int
  1335  }
  1336  type networkingCommandEntry_add_dhcp_mac_to_ip struct {
  1337  	vnet int
  1338  	mac  net.HardwareAddr
  1339  	ip   net.IP
  1340  }
  1341  type networkingCommandEntry_remove_dhcp_mac_to_ip struct {
  1342  	vnet int
  1343  	mac  net.HardwareAddr
  1344  }
  1345  type networkingCommandEntry_add_bridge_mapping struct {
  1346  	intf networkingInterface
  1347  	vnet int
  1348  }
  1349  type networkingCommandEntry_remove_bridge_mapping struct {
  1350  	intf networkingInterface
  1351  }
  1352  type networkingCommandEntry_add_nat_prefix struct {
  1353  	vnet   int
  1354  	prefix int
  1355  }
  1356  type networkingCommandEntry_remove_nat_prefix struct {
  1357  	vnet   int
  1358  	prefix int
  1359  }
  1360  
  1361  type networkingCommandEntry struct {
  1362  	entry                 interface{}
  1363  	answer                *networkingCommandEntry_answer
  1364  	remove_answer         *networkingCommandEntry_remove_answer
  1365  	add_nat_portfwd       *networkingCommandEntry_add_nat_portfwd
  1366  	remove_nat_portfwd    *networkingCommandEntry_remove_nat_portfwd
  1367  	add_dhcp_mac_to_ip    *networkingCommandEntry_add_dhcp_mac_to_ip
  1368  	remove_dhcp_mac_to_ip *networkingCommandEntry_remove_dhcp_mac_to_ip
  1369  	add_bridge_mapping    *networkingCommandEntry_add_bridge_mapping
  1370  	remove_bridge_mapping *networkingCommandEntry_remove_bridge_mapping
  1371  	add_nat_prefix        *networkingCommandEntry_add_nat_prefix
  1372  	remove_nat_prefix     *networkingCommandEntry_remove_nat_prefix
  1373  }
  1374  
  1375  func (e networkingCommandEntry) Name() string {
  1376  	switch e.entry.(type) {
  1377  	case networkingCommandEntry_answer:
  1378  		return "answer"
  1379  	case networkingCommandEntry_remove_answer:
  1380  		return "remove_answer"
  1381  	case networkingCommandEntry_add_nat_portfwd:
  1382  		return "add_nat_portfwd"
  1383  	case networkingCommandEntry_remove_nat_portfwd:
  1384  		return "remove_nat_portfwd"
  1385  	case networkingCommandEntry_add_dhcp_mac_to_ip:
  1386  		return "add_dhcp_mac_to_ip"
  1387  	case networkingCommandEntry_remove_dhcp_mac_to_ip:
  1388  		return "remove_dhcp_mac_to_ip"
  1389  	case networkingCommandEntry_add_bridge_mapping:
  1390  		return "add_bridge_mapping"
  1391  	case networkingCommandEntry_remove_bridge_mapping:
  1392  		return "remove_bridge_mapping"
  1393  	case networkingCommandEntry_add_nat_prefix:
  1394  		return "add_nat_prefix"
  1395  	case networkingCommandEntry_remove_nat_prefix:
  1396  		return "remove_nat_prefix"
  1397  	}
  1398  	return ""
  1399  }
  1400  
  1401  func (e networkingCommandEntry) Entry() reflect.Value {
  1402  	this := reflect.ValueOf(e)
  1403  	switch e.entry.(type) {
  1404  	case networkingCommandEntry_answer:
  1405  		return reflect.Indirect(this.FieldByName("answer"))
  1406  	case networkingCommandEntry_remove_answer:
  1407  		return reflect.Indirect(this.FieldByName("remove_answer"))
  1408  	case networkingCommandEntry_add_nat_portfwd:
  1409  		return reflect.Indirect(this.FieldByName("add_nat_portfwd"))
  1410  	case networkingCommandEntry_remove_nat_portfwd:
  1411  		return reflect.Indirect(this.FieldByName("remove_nat_portfwd"))
  1412  	case networkingCommandEntry_add_dhcp_mac_to_ip:
  1413  		return reflect.Indirect(this.FieldByName("add_dhcp_mac_to_ip"))
  1414  	case networkingCommandEntry_remove_dhcp_mac_to_ip:
  1415  		return reflect.Indirect(this.FieldByName("remove_dhcp_mac_to_ip"))
  1416  	case networkingCommandEntry_add_bridge_mapping:
  1417  		return reflect.Indirect(this.FieldByName("add_bridge_mapping"))
  1418  	case networkingCommandEntry_remove_bridge_mapping:
  1419  		return reflect.Indirect(this.FieldByName("remove_bridge_mapping"))
  1420  	case networkingCommandEntry_add_nat_prefix:
  1421  		return reflect.Indirect(this.FieldByName("add_nat_prefix"))
  1422  	case networkingCommandEntry_remove_nat_prefix:
  1423  		return reflect.Indirect(this.FieldByName("remove_nat_prefix"))
  1424  	}
  1425  	return reflect.Value{}
  1426  }
  1427  
  1428  func (e networkingCommandEntry) Repr() string {
  1429  	var result map[string]interface{}
  1430  	result = make(map[string]interface{})
  1431  
  1432  	entryN, entry := e.Name(), e.Entry()
  1433  	entryT := entry.Type()
  1434  	for i := 0; i < entry.NumField(); i++ {
  1435  		fld, fldT := entry.Field(i), entryT.Field(i)
  1436  		result[fldT.Name] = fld
  1437  	}
  1438  	return fmt.Sprintf("%s -> %v", entryN, result)
  1439  }
  1440  
  1441  // networking command entry parsers
  1442  func parseNetworkingCommand_answer(row []string) (*networkingCommandEntry, error) {
  1443  	if len(row) != 2 {
  1444  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
  1445  	}
  1446  	vnet := networkingVNET{value: row[0]}
  1447  	if !vnet.Valid() {
  1448  		return nil, fmt.Errorf("Invalid format for VNET.")
  1449  	}
  1450  	value := row[1]
  1451  
  1452  	result := networkingCommandEntry_answer{vnet: vnet, value: value}
  1453  	return &networkingCommandEntry{entry: result, answer: &result}, nil
  1454  }
  1455  func parseNetworkingCommand_remove_answer(row []string) (*networkingCommandEntry, error) {
  1456  	if len(row) != 1 {
  1457  		return nil, fmt.Errorf("Expected %d argument. Received %d.", 1, len(row))
  1458  	}
  1459  	vnet := networkingVNET{value: row[0]}
  1460  	if !vnet.Valid() {
  1461  		return nil, fmt.Errorf("Invalid format for VNET.")
  1462  	}
  1463  
  1464  	result := networkingCommandEntry_remove_answer{vnet: vnet}
  1465  	return &networkingCommandEntry{entry: result, remove_answer: &result}, nil
  1466  }
  1467  func parseNetworkingCommand_add_nat_portfwd(row []string) (*networkingCommandEntry, error) {
  1468  	if len(row) != 5 {
  1469  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 5, len(row))
  1470  	}
  1471  
  1472  	vnet, err := strconv.Atoi(row[0])
  1473  	if err != nil {
  1474  		return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
  1475  	}
  1476  
  1477  	protocol := strings.ToLower(row[1])
  1478  	if !(protocol == "tcp" || protocol == "udp") {
  1479  		return nil, fmt.Errorf("Expected \"tcp\" or \"udp\" for second argument. : %v", row[1])
  1480  	}
  1481  
  1482  	sport, err := strconv.Atoi(row[2])
  1483  	if err != nil {
  1484  		return nil, fmt.Errorf("Unable to parse third argument as an integer. : %v", row[2])
  1485  	}
  1486  
  1487  	dest := net.ParseIP(row[3])
  1488  	if dest == nil {
  1489  		return nil, fmt.Errorf("Unable to parse fourth argument as an IPv4 address. : %v", row[2])
  1490  	}
  1491  
  1492  	dport, err := strconv.Atoi(row[4])
  1493  	if err != nil {
  1494  		return nil, fmt.Errorf("Unable to parse fifth argument as an integer. : %v", row[4])
  1495  	}
  1496  
  1497  	result := networkingCommandEntry_add_nat_portfwd{vnet: vnet - 1, protocol: protocol, port: sport, target_host: dest, target_port: dport}
  1498  	return &networkingCommandEntry{entry: result, add_nat_portfwd: &result}, nil
  1499  }
  1500  func parseNetworkingCommand_remove_nat_portfwd(row []string) (*networkingCommandEntry, error) {
  1501  	if len(row) != 3 {
  1502  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 3, len(row))
  1503  	}
  1504  
  1505  	vnet, err := strconv.Atoi(row[0])
  1506  	if err != nil {
  1507  		return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
  1508  	}
  1509  
  1510  	protocol := strings.ToLower(row[1])
  1511  	if !(protocol == "tcp" || protocol == "udp") {
  1512  		return nil, fmt.Errorf("Expected \"tcp\" or \"udp\" for second argument. : %v", row[1])
  1513  	}
  1514  
  1515  	sport, err := strconv.Atoi(row[2])
  1516  	if err != nil {
  1517  		return nil, fmt.Errorf("Unable to parse third argument as an integer. : %v", row[2])
  1518  	}
  1519  
  1520  	result := networkingCommandEntry_remove_nat_portfwd{vnet: vnet - 1, protocol: protocol, port: sport}
  1521  	return &networkingCommandEntry{entry: result, remove_nat_portfwd: &result}, nil
  1522  }
  1523  func parseNetworkingCommand_add_dhcp_mac_to_ip(row []string) (*networkingCommandEntry, error) {
  1524  	if len(row) != 3 {
  1525  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 3, len(row))
  1526  	}
  1527  
  1528  	vnet, err := strconv.Atoi(row[0])
  1529  	if err != nil {
  1530  		return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
  1531  	}
  1532  
  1533  	mac, err := net.ParseMAC(row[1])
  1534  	if err != nil {
  1535  		return nil, fmt.Errorf("Unable to parse second argument as hwaddr. : %v", row[1])
  1536  	}
  1537  
  1538  	ip := net.ParseIP(row[2])
  1539  	if ip != nil {
  1540  		return nil, fmt.Errorf("Unable to parse third argument as ipv4. : %v", row[2])
  1541  	}
  1542  
  1543  	result := networkingCommandEntry_add_dhcp_mac_to_ip{vnet: vnet - 1, mac: mac, ip: ip}
  1544  	return &networkingCommandEntry{entry: result, add_dhcp_mac_to_ip: &result}, nil
  1545  }
  1546  func parseNetworkingCommand_remove_dhcp_mac_to_ip(row []string) (*networkingCommandEntry, error) {
  1547  	if len(row) != 2 {
  1548  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
  1549  	}
  1550  
  1551  	vnet, err := strconv.Atoi(row[0])
  1552  	if err != nil {
  1553  		return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
  1554  	}
  1555  
  1556  	mac, err := net.ParseMAC(row[1])
  1557  	if err != nil {
  1558  		return nil, fmt.Errorf("Unable to parse second argument as hwaddr. : %v", row[1])
  1559  	}
  1560  
  1561  	result := networkingCommandEntry_remove_dhcp_mac_to_ip{vnet: vnet - 1, mac: mac}
  1562  	return &networkingCommandEntry{entry: result, remove_dhcp_mac_to_ip: &result}, nil
  1563  }
  1564  func parseNetworkingCommand_add_bridge_mapping(row []string) (*networkingCommandEntry, error) {
  1565  	if len(row) != 2 {
  1566  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
  1567  	}
  1568  	intf := networkingInterface{name: row[0]}
  1569  
  1570  	vnet, err := strconv.Atoi(row[1])
  1571  	if err != nil {
  1572  		return nil, fmt.Errorf("Unable to parse second argument as an integer. : %v", row[2])
  1573  	}
  1574  
  1575  	result := networkingCommandEntry_add_bridge_mapping{intf: intf, vnet: vnet - 1}
  1576  	return &networkingCommandEntry{entry: result, add_bridge_mapping: &result}, nil
  1577  }
  1578  func parseNetworkingCommand_remove_bridge_mapping(row []string) (*networkingCommandEntry, error) {
  1579  	if len(row) != 1 {
  1580  		return nil, fmt.Errorf("Expected %d argument. Received %d.", 1, len(row))
  1581  	}
  1582  	intf := networkingInterface{name: row[0]}
  1583  	/*
  1584  		number, err := strconv.Atoi(row[0])
  1585  		if err != nil {
  1586  			return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
  1587  		}
  1588  	*/
  1589  	result := networkingCommandEntry_remove_bridge_mapping{intf: intf}
  1590  	return &networkingCommandEntry{entry: result, remove_bridge_mapping: &result}, nil
  1591  }
  1592  func parseNetworkingCommand_add_nat_prefix(row []string) (*networkingCommandEntry, error) {
  1593  	if len(row) != 2 {
  1594  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
  1595  	}
  1596  
  1597  	vnet, err := strconv.Atoi(row[0])
  1598  	if err != nil {
  1599  		return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
  1600  	}
  1601  
  1602  	if !strings.HasPrefix(row[1], "/") {
  1603  		return nil, fmt.Errorf("Expected second argument to begin with \"/\". : %v", row[1])
  1604  	}
  1605  
  1606  	prefix, err := strconv.Atoi(row[1][1:])
  1607  	if err != nil {
  1608  		return nil, fmt.Errorf("Unable to parse prefix out of second argument. : %v", row[1])
  1609  	}
  1610  
  1611  	result := networkingCommandEntry_add_nat_prefix{vnet: vnet - 1, prefix: prefix}
  1612  	return &networkingCommandEntry{entry: result, add_nat_prefix: &result}, nil
  1613  }
  1614  func parseNetworkingCommand_remove_nat_prefix(row []string) (*networkingCommandEntry, error) {
  1615  	if len(row) != 2 {
  1616  		return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
  1617  	}
  1618  
  1619  	vnet, err := strconv.Atoi(row[0])
  1620  	if err != nil {
  1621  		return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
  1622  	}
  1623  
  1624  	if !strings.HasPrefix(row[1], "/") {
  1625  		return nil, fmt.Errorf("Expected second argument to begin with \"/\". : %v", row[1])
  1626  	}
  1627  	prefix, err := strconv.Atoi(row[1][1:])
  1628  	if err != nil {
  1629  		return nil, fmt.Errorf("Unable to parse prefix out of second argument. : %v", row[1])
  1630  	}
  1631  
  1632  	result := networkingCommandEntry_remove_nat_prefix{vnet: vnet - 1, prefix: prefix}
  1633  	return &networkingCommandEntry{entry: result, remove_nat_prefix: &result}, nil
  1634  }
  1635  
  1636  type networkingCommandParser struct {
  1637  	command  string
  1638  	callback func([]string) (*networkingCommandEntry, error)
  1639  }
  1640  
  1641  var NetworkingCommandParsers = []networkingCommandParser{
  1642  	/* DictRecordParseFunct */ {command: "answer", callback: parseNetworkingCommand_answer},
  1643  	/* DictRecordParseFunct */ {command: "remove_answer", callback: parseNetworkingCommand_remove_answer},
  1644  	/* NatFwdRecordParseFunct */ {command: "add_nat_portfwd", callback: parseNetworkingCommand_add_nat_portfwd},
  1645  	/* NatFwdRecordParseFunct */ {command: "remove_nat_portfwd", callback: parseNetworkingCommand_remove_nat_portfwd},
  1646  	/* DhcpMacRecordParseFunct */ {command: "add_dhcp_mac_to_ip", callback: parseNetworkingCommand_add_dhcp_mac_to_ip},
  1647  	/* DhcpMacRecordParseFunct */ {command: "remove_dhcp_mac_to_ip", callback: parseNetworkingCommand_remove_dhcp_mac_to_ip},
  1648  	/* BridgeMappingRecordParseFunct */ {command: "add_bridge_mapping", callback: parseNetworkingCommand_add_bridge_mapping},
  1649  	/* BridgeMappingRecordParseFunct */ {command: "remove_bridge_mapping", callback: parseNetworkingCommand_remove_bridge_mapping},
  1650  	/* NatPrefixRecordParseFunct */ {command: "add_nat_prefix", callback: parseNetworkingCommand_add_nat_prefix},
  1651  	/* NatPrefixRecordParseFunct */ {command: "remove_nat_prefix", callback: parseNetworkingCommand_remove_nat_prefix},
  1652  }
  1653  
  1654  func NetworkingParserByCommand(command string) *func([]string) (*networkingCommandEntry, error) {
  1655  	for _, p := range NetworkingCommandParsers {
  1656  		if p.command == command {
  1657  			return &p.callback
  1658  		}
  1659  	}
  1660  	return nil
  1661  }
  1662  
  1663  func parseNetworkingConfig(eof sentinelSignaller, rows chan []string) (chan networkingCommandEntry, sentinelSignaller) {
  1664  	var out chan networkingCommandEntry
  1665  
  1666  	eop := make(sentinelSignaller)
  1667  
  1668  	out = make(chan networkingCommandEntry)
  1669  	go func(in chan []string, out chan networkingCommandEntry) {
  1670  		for reading := true; reading; {
  1671  			select {
  1672  			case <-eof:
  1673  				reading = false
  1674  			case row := <-in:
  1675  				if len(row) >= 1 {
  1676  					parser := NetworkingParserByCommand(row[0])
  1677  					if parser == nil {
  1678  						log.Printf("Invalid command : %v", row)
  1679  						continue
  1680  					}
  1681  					callback := *parser
  1682  					entry, err := callback(row[1:])
  1683  					if err != nil {
  1684  						log.Printf("Unable to parse command : %v %v", err, row)
  1685  						continue
  1686  					}
  1687  					out <- *entry
  1688  				}
  1689  			}
  1690  		}
  1691  		close(eop)
  1692  	}(rows, out)
  1693  	return out, eop
  1694  }
  1695  
  1696  type NetworkingConfig struct {
  1697  	answer         map[int]map[string]string
  1698  	nat_portfwd    map[int]map[string]string
  1699  	dhcp_mac_to_ip map[int]map[string]net.IP
  1700  	//bridge_mapping map[net.Interface]uint64	// XXX: we don't need the actual interface for anything but informing the user.
  1701  	bridge_mapping map[string]int
  1702  	nat_prefix     map[int][]int
  1703  }
  1704  
  1705  func (c NetworkingConfig) repr() string {
  1706  	return fmt.Sprintf("answer -> %v\nnat_portfwd -> %v\ndhcp_mac_to_ip -> %v\nbridge_mapping -> %v\nnat_prefix -> %v", c.answer, c.nat_portfwd, c.dhcp_mac_to_ip, c.bridge_mapping, c.nat_prefix)
  1707  }
  1708  
  1709  func flattenNetworkingConfig(eof sentinelSignaller, in chan networkingCommandEntry) NetworkingConfig {
  1710  	var result NetworkingConfig
  1711  	var vmnet int
  1712  
  1713  	result.answer = make(map[int]map[string]string)
  1714  	result.nat_portfwd = make(map[int]map[string]string)
  1715  	result.dhcp_mac_to_ip = make(map[int]map[string]net.IP)
  1716  	result.bridge_mapping = make(map[string]int)
  1717  	result.nat_prefix = make(map[int][]int)
  1718  
  1719  	for reading := true; reading; {
  1720  		select {
  1721  		case <-eof:
  1722  			reading = false
  1723  		case e := <-in:
  1724  			switch e.entry.(type) {
  1725  			case networkingCommandEntry_answer:
  1726  				vnet := e.answer.vnet
  1727  				answers, exists := result.answer[vnet.Number()]
  1728  				if !exists {
  1729  					answers = make(map[string]string)
  1730  					result.answer[vnet.Number()] = answers
  1731  				}
  1732  				answers[vnet.Option()] = e.answer.value
  1733  			case networkingCommandEntry_remove_answer:
  1734  				vnet := e.remove_answer.vnet
  1735  				answers, exists := result.answer[vnet.Number()]
  1736  				if exists {
  1737  					delete(answers, vnet.Option())
  1738  				} else {
  1739  					log.Printf("Unable to remove answer %s as specified by `remove_answer`.\n", vnet.Repr())
  1740  				}
  1741  			case networkingCommandEntry_add_nat_portfwd:
  1742  				vmnet = e.add_nat_portfwd.vnet
  1743  				protoport := fmt.Sprintf("%s/%d", e.add_nat_portfwd.protocol, e.add_nat_portfwd.port)
  1744  				target := fmt.Sprintf("%s:%d", e.add_nat_portfwd.target_host, e.add_nat_portfwd.target_port)
  1745  				portfwds, exists := result.nat_portfwd[vmnet]
  1746  				if !exists {
  1747  					portfwds = make(map[string]string)
  1748  					result.nat_portfwd[vmnet] = portfwds
  1749  				}
  1750  				portfwds[protoport] = target
  1751  			case networkingCommandEntry_remove_nat_portfwd:
  1752  				vmnet = e.remove_nat_portfwd.vnet
  1753  				protoport := fmt.Sprintf("%s/%d", e.remove_nat_portfwd.protocol, e.remove_nat_portfwd.port)
  1754  				portfwds, exists := result.nat_portfwd[vmnet]
  1755  				if exists {
  1756  					delete(portfwds, protoport)
  1757  				} else {
  1758  					log.Printf("Unable to remove nat port-forward %s from interface %s%d as requested by `remove_nat_portfwd`.\n", protoport, NetworkingInterfacePrefix, vmnet)
  1759  				}
  1760  			case networkingCommandEntry_add_dhcp_mac_to_ip:
  1761  				vmnet = e.add_dhcp_mac_to_ip.vnet
  1762  				dhcpmacs, exists := result.dhcp_mac_to_ip[vmnet]
  1763  				if !exists {
  1764  					dhcpmacs = make(map[string]net.IP)
  1765  					result.dhcp_mac_to_ip[vmnet] = dhcpmacs
  1766  				}
  1767  				dhcpmacs[e.add_dhcp_mac_to_ip.mac.String()] = e.add_dhcp_mac_to_ip.ip
  1768  			case networkingCommandEntry_remove_dhcp_mac_to_ip:
  1769  				vmnet = e.remove_dhcp_mac_to_ip.vnet
  1770  				dhcpmacs, exists := result.dhcp_mac_to_ip[vmnet]
  1771  				if exists {
  1772  					delete(dhcpmacs, e.remove_dhcp_mac_to_ip.mac.String())
  1773  				} else {
  1774  					log.Printf("Unable to remove dhcp_mac_to_ip entry %v from interface %s%d as specified by `remove_dhcp_mac_to_ip`.\n", e.remove_dhcp_mac_to_ip, NetworkingInterfacePrefix, vmnet)
  1775  				}
  1776  			case networkingCommandEntry_add_bridge_mapping:
  1777  				intf := e.add_bridge_mapping.intf
  1778  				if _, err := intf.Interface(); err != nil {
  1779  					log.Printf("Interface \"%s\" as specified by `add_bridge_mapping` was not found on the current platform. This is a non-critical error. Ignoring.", intf.name)
  1780  				}
  1781  				result.bridge_mapping[intf.name] = e.add_bridge_mapping.vnet
  1782  			case networkingCommandEntry_remove_bridge_mapping:
  1783  				intf := e.remove_bridge_mapping.intf
  1784  				if _, err := intf.Interface(); err != nil {
  1785  					log.Printf("Interface \"%s\" as specified by `remove_bridge_mapping` was not found on the current platform. This is a non-critical error. Ignoring.", intf.name)
  1786  				}
  1787  				delete(result.bridge_mapping, intf.name)
  1788  			case networkingCommandEntry_add_nat_prefix:
  1789  				vmnet = e.add_nat_prefix.vnet
  1790  				_, exists := result.nat_prefix[vmnet]
  1791  				if exists {
  1792  					result.nat_prefix[vmnet] = append(result.nat_prefix[vmnet], e.add_nat_prefix.prefix)
  1793  				} else {
  1794  					result.nat_prefix[vmnet] = []int{e.add_nat_prefix.prefix}
  1795  				}
  1796  			case networkingCommandEntry_remove_nat_prefix:
  1797  				vmnet = e.remove_nat_prefix.vnet
  1798  				prefixes, exists := result.nat_prefix[vmnet]
  1799  				if exists {
  1800  					for index := 0; index < len(prefixes); index++ {
  1801  						if prefixes[index] == e.remove_nat_prefix.prefix {
  1802  							result.nat_prefix[vmnet] = append(prefixes[:index], prefixes[index+1:]...)
  1803  							break
  1804  						}
  1805  					}
  1806  				} else {
  1807  					log.Printf("Unable to remove nat prefix /%d from interface %s%d as specified by `remove_nat_prefix`.\n", e.remove_nat_prefix.prefix, NetworkingInterfacePrefix, vmnet)
  1808  				}
  1809  			}
  1810  		}
  1811  	}
  1812  	return result
  1813  }
  1814  
  1815  // Constructor for networking file
  1816  func ReadNetworkingConfig(fd *os.File) (NetworkingConfig, error) {
  1817  	// start piecing together different parts of the file
  1818  	fromfile, eof := consumeFile(fd)
  1819  	tokenized, eot := tokenizeNetworkingConfig(eof, fromfile)
  1820  	rows, eos := splitNetworkingConfig(eot, tokenized)
  1821  	entries, eop := parseNetworkingConfig(eos, rows)
  1822  
  1823  	// parse the version
  1824  	parsed_version, err := networkingReadVersion(<-rows)
  1825  	if err != nil {
  1826  		return NetworkingConfig{}, err
  1827  	}
  1828  
  1829  	// verify that it's 1.0 since that's all we support.
  1830  	version := parsed_version.Number()
  1831  	if version != 1.0 {
  1832  		return NetworkingConfig{}, fmt.Errorf("Expected version %f of networking file. Received version %f.", 1.0, version)
  1833  	}
  1834  
  1835  	// convert to a configuration
  1836  	result := flattenNetworkingConfig(eop, entries)
  1837  	return result, nil
  1838  }
  1839  
  1840  // netmapper interface
  1841  type NetworkingType int
  1842  
  1843  const (
  1844  	NetworkingType_HOSTONLY = iota + 1
  1845  	NetworkingType_NAT
  1846  	NetworkingType_BRIDGED
  1847  )
  1848  
  1849  func networkingConfig_InterfaceTypes(config NetworkingConfig) map[int]NetworkingType {
  1850  	var result map[int]NetworkingType
  1851  	result = make(map[int]NetworkingType)
  1852  
  1853  	// defaults
  1854  	result[0] = NetworkingType_BRIDGED
  1855  	result[1] = NetworkingType_HOSTONLY
  1856  	result[8] = NetworkingType_NAT
  1857  
  1858  	// walk through config collecting bridged interfaces
  1859  	for _, vmnet := range config.bridge_mapping {
  1860  		result[vmnet] = NetworkingType_BRIDGED
  1861  	}
  1862  
  1863  	// walk through answers finding out which ones are nat versus hostonly
  1864  	for vmnet, table := range config.answer {
  1865  		// everything should be defined as a virtual adapter...
  1866  		if table["VIRTUAL_ADAPTER"] == "yes" {
  1867  
  1868  			// validate that the VNET entry contains everything we expect it to
  1869  			_, subnetQ := table["HOSTONLY_SUBNET"]
  1870  			_, netmaskQ := table["HOSTONLY_NETMASK"]
  1871  			if !(subnetQ && netmaskQ) {
  1872  				log.Printf("Interface %s%d is missing some expected keys (HOSTONLY_SUBNET, HOSTONLY_NETMASK). This is non-critical. Ignoring..", NetworkingInterfacePrefix, vmnet)
  1873  			}
  1874  
  1875  			// distinguish between nat or hostonly
  1876  			if table["NAT"] == "yes" {
  1877  				result[vmnet] = NetworkingType_NAT
  1878  			} else {
  1879  				result[vmnet] = NetworkingType_HOSTONLY
  1880  			}
  1881  
  1882  			// if it's not a virtual_adapter, then it must be an alias (really a bridge).
  1883  		} else {
  1884  			result[vmnet] = NetworkingType_BRIDGED
  1885  		}
  1886  	}
  1887  	return result
  1888  }
  1889  
  1890  func networkingConfig_NamesToVmnet(config NetworkingConfig) map[NetworkingType][]int {
  1891  	types := networkingConfig_InterfaceTypes(config)
  1892  
  1893  	// now sort the keys
  1894  	var keys []int
  1895  	for vmnet := range types {
  1896  		keys = append(keys, vmnet)
  1897  	}
  1898  	sort.Ints(keys)
  1899  
  1900  	// build result dictionary
  1901  	var result map[NetworkingType][]int
  1902  	result = make(map[NetworkingType][]int)
  1903  	for i := 0; i < len(keys); i++ {
  1904  		t := types[keys[i]]
  1905  		result[t] = append(result[t], keys[i])
  1906  	}
  1907  	return result
  1908  }
  1909  
  1910  const NetworkingInterfacePrefix = "vmnet"
  1911  
  1912  func (e NetworkingConfig) NameIntoDevices(name string) ([]string, error) {
  1913  	netmapper := networkingConfig_NamesToVmnet(e)
  1914  	name = strings.ToLower(name)
  1915  
  1916  	var vmnets []string
  1917  	var networkingType NetworkingType
  1918  	if name == "hostonly" && len(netmapper[NetworkingType_HOSTONLY]) > 0 {
  1919  		networkingType = NetworkingType_HOSTONLY
  1920  	} else if name == "nat" && len(netmapper[NetworkingType_NAT]) > 0 {
  1921  		networkingType = NetworkingType_NAT
  1922  	} else if name == "bridged" && len(netmapper[NetworkingType_BRIDGED]) > 0 {
  1923  		networkingType = NetworkingType_BRIDGED
  1924  	} else {
  1925  		return make([]string, 0), fmt.Errorf("Network name not found: %v", name)
  1926  	}
  1927  
  1928  	for i := 0; i < len(netmapper[networkingType]); i++ {
  1929  		vmnets = append(vmnets, fmt.Sprintf("%s%d", NetworkingInterfacePrefix, netmapper[networkingType][i]))
  1930  	}
  1931  	return vmnets, nil
  1932  }
  1933  
  1934  func (e NetworkingConfig) DeviceIntoName(device string) (string, error) {
  1935  	types := networkingConfig_InterfaceTypes(e)
  1936  
  1937  	lowerdevice := strings.ToLower(device)
  1938  	if !strings.HasPrefix(lowerdevice, NetworkingInterfacePrefix) {
  1939  		return device, nil
  1940  	}
  1941  	vmnet, err := strconv.Atoi(lowerdevice[len(NetworkingInterfacePrefix):])
  1942  	if err != nil {
  1943  		return "", err
  1944  	}
  1945  	network := types[vmnet]
  1946  	switch network {
  1947  	case NetworkingType_HOSTONLY:
  1948  		return "hostonly", nil
  1949  	case NetworkingType_NAT:
  1950  		return "nat", nil
  1951  	case NetworkingType_BRIDGED:
  1952  		return "bridged", nil
  1953  	}
  1954  	return "", fmt.Errorf("Unable to determine network type for device %s%d.", NetworkingInterfacePrefix, vmnet)
  1955  }
  1956  
  1957  /** generic async file reader */
  1958  func consumeFile(fd *os.File) (chan byte, sentinelSignaller) {
  1959  	fromfile := make(chan byte)
  1960  	eof := make(sentinelSignaller)
  1961  	go func() {
  1962  		b := make([]byte, 1)
  1963  		for {
  1964  			_, err := fd.Read(b)
  1965  			if err == io.EOF {
  1966  				break
  1967  			}
  1968  			fromfile <- b[0]
  1969  		}
  1970  		close(eof)
  1971  	}()
  1972  	return fromfile, eof
  1973  }