# Funkensign


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 &mdash;
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](https://github.com/miekg/godns/raw/master/_examples/funkensturm/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


