Bad format when transforming json

Hello,

I get wierd chars when i do json. if leave it with json i don’t get jiberish, but i don’t get the key names either. Any advice on what i am doing wrong?

[{0 0 ACCEPT all -- * * 1.2.3.4/32 0.0.0.0/0 }
package main

import (
        "fmt"
        "encoding/json"
        "github.com/coreos/go-iptables/iptables"
)


func main() {
        ipt, _ := iptables.New()

        listTab, _ := ipt.StructuredStats("filter","FROM_API")
        jsonAPI, _ := json.MarshalIndent(listTab, "", "  ")

        fmt.Println(string(jsonAPI))


}

the output of Mask is jibberish

[
  {
    "pkts": 0,
    "bytes": 0,
    "target": "ACCEPT",
    "prot": "all",
    "opt": "--",
    "in": "*",
    "out": "*",
    "source": {
      "IP": "1.2.3.4",
      "Mask": "/////w=="
    },
    "destination": {
      "IP": "0.0.0.0",
      "Mask": "AAAAAA=="
    },
    "options": ""
  }]

It’s not gibberish, its base64 encoded data.

The original data is probably in a byte[] or similar.

and how can i dynamically decode it ?

Hi, @mistergo, welcome to the forum!

Go’s documentation is pretty thorough, but I’ll admit that sometimes it’s hard to see how different packages interact, which is what’s happening here between the net and encoding/json packages:

Explanation

I looked up the documentation for that package’s IPTables.StructuredStats function and saw that it returns a slice of Stat types.

That type’s Source and Destination fields are of type net.IPNet which itself has the IP and Mask fields that you’re seeing.

The json.Marshal function’s documentation says this:

If an encountered value implements the Marshaler interface and is not a nil pointer, Marshal calls its MarshalJSON method to produce JSON. If no MarshalJSON method is present but the value implements encoding.TextMarshaler instead, Marshal calls its MarshalText method and encodes the result as a JSON string.

(emphasis mine)

The IP field has type net.IP and that type has a MarshalText method, so when you marshal it to JSON, you get a nice string representation. The Mask field is of type IPMask and it does not have a MarshalText method, so you get the default behavior of marshaling IPMask’s backing type: []byte. The Marshal documentation says this about []byte:

Array and slice values encode as JSON arrays, except that []byte encodes as a base64-encoded string, and a nil slice encodes as the null JSON value.

(emphasis mine)

So that explains why the Mask field is appearing as base-64: It does not have a MarshalJSON, or MarshalText, and its backing type is []byte which is encoded as base-64 by default.

Question

So my question is: Can you clarify what you mean by “dynamically decode?” If you want to marshal into JSON with a different format, you will have to define your own structure and maybe your own MarshalText/MarshalJSON methods. We can give you more specific answers if you can clarify what it is you would like to see instead of what you’re getting.

1 Like

Thanks @skillian for clarifing why i get the values encoded. As for what I want, is to display the value of Mask human - readable and not base64encode.

Does human readable mean, dotted-decimal like 255.255.255.0? Or CIDR, like: /24? If dotted-decimal, what about for IPv6 addresses?

Thanks @skillian for the reply! Any of those two (CIDR or dotted-decimal) will work as for ipv6 is not used, any ideas how to do this?

The only way I can think of is by copying the struct definition (and the definitions of any sub-structures; in this case *net.IPNet), replacing any of the references in the copied structs to the other copied types, and then manually copying all the fields over: Go Playground - The Go Programming Language

1 Like

Thanks, for the help!