0

Haven't had any luck parsing this snippet of xml text from the output of nmap. I'm interested in parsing the protocol, portid and reason fields out of the xml text. Initially, I tried extracting only the first two fields:

var data = []byte(`
 <ports><extraports state="filtered" count="65526">
    <extrareasons reason="no-responses" count="65526"/>
    </extraports>
    <port protocol="tcp" portid="1"><state state="closed" reason="conn-refused" reason_ttl="0"/><service name="tcpmux" method="table" conf="3"/></port>
    <port protocol="tcp" portid="2"><state state="closed" reason="conn-refused" reason_ttl="0"/><service name="compressnet" method="table" conf="3"/></port>
    <port protocol="tcp" portid="8"><state state="closed" reason="conn-refused" reason_ttl="0"/><service name="unknown" method="table" conf="3"/></port>
    <port protocol="tcp" portid="2709"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="7748"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="12946"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="53094"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="58137"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="63139"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    </ports>
`)

I defined my structures as below:

type PortData struct {
    Protocol string `xml:"protocol,attr"`
    Port uint32 `xml:"portid,attr"`
}

type Nmap struct {
    IgnoreMe xml.Name `xml:"ports"`
    Data []PortData `xml:"port"`    
}

func main() {
    var m Nmap
    if err := xml.Unmarshal(data, &m); err == nil {
        log.Fatalln(err)
    }
    log.Println("Succeeded")
    fmt.Printf("%#v\n", m)
}

How can I fix my struct definitions to extract the fields of interest? Thanks

2 Answers 2

2

You can extract the reason field by updating your structs to read:

type State struct {
    Reason string `xml:"reason,attr"`
}

type PortData struct {
    Protocol string `xml:"protocol,attr"`
    Port     uint32 `xml:"portid,attr"`
    State    State  `xml:"state"`
}

Unfortunately you can't decode the reason attribute into a PortData field. While the package does support picking nested elements, it won't let you combine that with attribute selection (i.e. xml:"state>reason,attr" will result in an error from Unmarshal).

Secondly, there is a small error in your test program: you are bailing out when err is nil, rather than the reverse. With those two changes you should be able to extract the data you're after.

You can experiment with this at: http://play.golang.org/p/hVxLzZ03cC

Sign up to request clarification or add additional context in comments.

Comments

1

You just have a typo. It should be err != nil.

3 Comments

The other answer points out this error and provides other information besides. Only add a new answer if you have something new to add.
When I started writing the answer (and testing the code to ensure there were no other errors), there was no other answer to the question. I'll try to remember to reload the question just before submitting the answer so that I don't submit an answer if it's already covered by someone else in the mean-time. I'm a new user, so I'm not aware of the best-practices regarding this.
Don't worry about it; I wouldn't have said anything if I'd noticed the answers were posted so closely together.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.