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 —
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.
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