How about on-the-fly signing? In this example we add a signature to any packet dealing with www.example.org. Again it is a matter of defining the matching, action and setup functions.

Matching

We don’t have to match anything coming in, we only need to sign pkts on their way out. So the function becomes:

func match(m *dns.Msg, d int) (*dns.Msg, bool) {
        // Matching criteria
        switch d { 
        case IN: 
                // nothing
        case OUT:
                // nothing
        }   
        // Packet Mangling
        switch d { 
        case IN: 
                // nothing
        case OUT:
                if m.Question[0].Name == "www.example.org." {
                        // On the way out sign the packet
                        m = sign(m) // keys are global
                }   
        }   
        return m, true
}

As you can see, it calls the sign() function where the actual signing takes place. We just sign the first RR in the answer section — if there is one.

func sign(m *dns.Msg) *dns.Msg {
        // Setup the signature
        sg := new(dns.RR_RRSIG)
        sg.Hdr = dns.RR_Header{"www.example.org.", dns.TypeRRSIG, dns.ClassINET, 14400, 0}
        sg.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
        sg.Inception = 1293942305  // date -u '+%s' -d"2011-01-02 04:25:05"
        sg.KeyTag = pubkey.KeyTag()   // pubkey is global
        sg.SignerName = pubkey.Hdr.Name
        sg.Algorithm = dns.AlgRSASHA256
                        
        if len(m.Answer) > 0 {
                // sign the first record
                an := m.Answer[0]
                sg.TypeCovered = an.Header().Rrtype
                sg.Labels = dns.LabelCount(an.Header().Name)
                sg.OrigTtl = an.Header().Ttl
                switch p:=privkey.(type) {
                        case *rsa.PrivateKey:
                        sg.Sign(p, []dns.RR{an})
                }
        }
        m.Answer = append(m.Answer, sg)
        return m
}               

Action function

Trivial, just forward the packet to the server and return the reply.

Setup

This is slight more tricky as we need to configure the signing key. Note the variables holding the key (pubkey and privkey) need to be global.

func setup() bool {
        privdata := `Private-key-format: v1.3
Algorithm: 5 (RSASHA1)
Modulus: AaTnz33zSgSIWzUBSJwerZiUdsTmfQNaB+AKpN8FnVlhGOfabJ6ZCi123hjOr3ucE/LWfPGtmEppuFf2dmuJW/yO6s8td5q5b81PUOt+uPMNBGJ1T4DUO8sOQQp4SXw76Q7KIgcrj2RSuN
PublicExponent: AQAB
PrivateExponent: /IkdBCupeEi7uHS5tPnvHAHPtNm5nf4xhWm9fBYpT0wjnlB+JTYbViXgoa+4uAhwK54nPvXxzovZz+UPLfwvFBoG3D0vYS+M9WWOBCnEuDK0MfcBWfTE2hlV13xDll1o7Pj/fv
Prime1: AdG+8ixEeDzHKI2GRD7lGhrQ8EzN4Tc0mek1u6ioFZ0imohaPqtqNq7RWVo35cWuvYflhFQYzFn99HGRvfGfDv8=
Prime2: 51psvlotBXuaqzrgfb5I6u7DG9JhU5WO68PZf1RMmq2e2xLvKvDGXCP5oFur9AOsHdbmahnzgFC1s18vg7kFLw==
Exponent1: glXRJ5oxm7CQJKrCRmeOmpqF5Lhooi5SM/UZguUmx0Z7wFSg3Q9oJhvnyVuDLYLs/y63jWEzLqvm0DFc2lUMuQ==
Exponent2: Aq3qan3y3Yhj7y28YdhtUcM4IT9bfzNRN2vKPg5E4Nm36EOc33twYKrN/kxxfl74hFPz0TDBwC+vGwe0LitbYw==
Coefficient: AZX3xIGzo/3fw4ouA6nAjpiWGpTK+OdFRkZtvbmzwgqnFDQopB0SweVnd1shpKCXkPTkdvpLTdmhU/84CW5m7cQ=
Created: 20110122104659
Publish: 20110122104659
Activate: 20110122104659`
        pubkey = new(dns.RR_DNSKEY)
        privkey, _ = pubkey.PrivateKeySetString(privdata)
        pubkey.Hdr = dns.RR_Header{"miek.nl.", dns.TypeDNSKEY, dns.ClassINET, 3600, 0}
        pubkey.Protocol = 3
        pubkey.Flags = 256
        return true
}       

Preparing the funkensturm struct

// Return the configration
func funkensturm() *Funkensturm {
        f := new(Funkensturm)
        f.Setup = setup
        f.Matches = make([]Match, 1)
        f.Matches[0].Op = AND
        f.Matches[0].Func = match
        f.Actions = make([]Action, 1)
        f.Actions[0].Func = delay
        return f
}

Now we can test.

Full source of config_sign.go

You have been signed

First a normal query for the A record of www.example.org

% dig +noidentify +nostats +nocmd +noauth +noadd www.example.org

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51771
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2

;; QUESTION SECTION:
;www.example.org.               IN      A

;; ANSWER SECTION:
www.example.org.        164813  IN      A       192.0.32.10

And, yes, I know example.org is signed, the query with +dnssec gives an RRSIG for www.example.org: (slight abbreviated):

    www.example.org.  172757 IN RRSIG   A 8 3 172800 20110131113433 20110124082514 15681 example.org. rr/Y2ZI3zZVQ5UC//u/* ... */TWC4rDxbI=

Note the signing key-id is 15681.

Now we put Funkensturm in between.

% dig -p 8053 +noidentify +nostats +nocmd +noauth +noadd www.example.org

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59821
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 2

;; QUESTION SECTION:
;www.example.org.               IN      A

;; ANSWER SECTION:
www.example.org.        164760  IN      A       192.0.32.10
www.example.org.        14400   IN      RRSIG   A 8 3 164760 20110201042505 20110102042505 21798 miek.nl. KV5RIVGWx0y9/* ... */vb6QjVygvG+cJ9gA

A signature has been added and note the signing key-id: 21798 and the owner of the key miek.nl.! Totally bogus, but nicely inserted anyway.

A dig-query with dnssec enabled is also interesting:

% dig -p 8053 +noidentify +nostats +nocmd +noauth +noadd www.example.org +dnssec  

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46834
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 3, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;www.example.org.               IN      A

;; ANSWER SECTION:
www.example.org.        164501  IN      A       192.0.32.10
www.example.org.        164501  IN      RRSIG   A 8 3 172800 20110131154555 20110124052517 15681 example.org. SPzKR3Xv1p/* ... */gm9kEghQoCDEA
www.example.org.        14400   IN      RRSIG   A 8 3 164501 20110201042505 20110102042505 21798 miek.nl. xKRv/hsry4y7Am/* ....*/vqeoBcpmdm+msA

The possibilities are endless.

I know you’re out there. I can feel you now. I know that you’re afraid. You’re afraid of us. You’re afraid of change. I don’t know the future. I didn’t come here to tell you how this is going to end. I came here to tell you how it’s going to begin. I’m going to hang up this phone, and then I’m going to show these people what you don’t want them to see. I’m going to show them a world … without you. A world without rules and controls, without borders or boundaries; a world where anything is possible. Where we go from there is a choice I leave to you.

Neo