1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
package libhosty
import (
"io/ioutil"
"net"
"strings"
)
//ParseHostsFile parse a hosts file from the given location.
// error is not nil if something goes wrong
func ParseHostsFile(path string) ([]HostsFileLine, error) {
byteData, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return parser(byteData)
}
//ParseHostsFileAsString parse a hosts file from a given string.
// error is not nil if something goes wrong
func ParseHostsFileAsString(stringData string) ([]HostsFileLine, error) {
bytesData := []byte(stringData)
return parser(bytesData)
}
func parser(bytesData []byte) ([]HostsFileLine, error) {
byteDataNormalized := strings.Replace(string(bytesData), "\r\n", "\n", -1)
fileLines := strings.Split(byteDataNormalized, "\n")
hostsFileLines := make([]HostsFileLine, len(fileLines))
// trim leading an trailing whitespace
for i, l := range fileLines {
curLine := &hostsFileLines[i]
curLine.Number = i
curLine.Raw = l
// trim line
curLine.trimed = strings.TrimSpace(l)
// check if it's an empty line
if curLine.trimed == "" {
curLine.Type = LineTypeEmpty
continue
}
// check if line starts with a #
if strings.HasPrefix(curLine.trimed, "#") {
// this can be a comment or a commented host line
// so remove the 1st char (#), trim spaces
// and try to parse the line as a host line
noCommentLine := strings.TrimPrefix(curLine.trimed, "#")
tmpParts := strings.Fields(strings.TrimSpace(noCommentLine))
// check what we have
switch len(tmpParts) {
case 0:
// empty line, comment line
curLine.Type = LineTypeComment
continue
default:
// non-empty line, try to parse as address
address := net.ParseIP(tmpParts[0])
// if address is nil this line is a comment
if address == nil {
curLine.Type = LineTypeComment
continue
}
}
// otherwise it is a commented line so let's try to parse it as a normal line
curLine.IsCommented = true
curLine.trimed = noCommentLine
}
// not a comment or empty line so try to parse it
// check if it contains a comment
curLineSplit := strings.SplitN(curLine.trimed, "#", 2)
if len(curLineSplit) > 1 {
// trim spaces from comments
curLine.Comment = strings.TrimSpace(curLineSplit[1])
}
curLine.trimed = curLineSplit[0]
curLine.Parts = strings.Fields(curLine.trimed)
if len(curLine.Parts) > 1 {
// parse address to ensure we have a valid address line
tmpIP := net.ParseIP(curLine.Parts[0])
if tmpIP != nil {
curLine.Type = LineTypeAddress
curLine.Address = tmpIP
// lower case all
for _, p := range curLine.Parts[1:] {
curLine.Hostnames = append(curLine.Hostnames, strings.ToLower(p))
}
continue
}
}
// if we can't figure out what this line is mark it as unknown
curLine.Type = LineTypeUnknown
}
// normalize slice
hostsFileLines = hostsFileLines[:]
return hostsFileLines, nil
}
|