# Funkensturm: delaying proxy example


Another application for Funkensturm is: delaying packets.
Here we only delay packets with the recursion desired bit (RD)
set, but it can be easily be changed to check for other 
properties of a packet, see `godoc dns` for all elements of 
DNS packets.

The configuration is similar as described
[here](/2011/january/23/funkensturm-transparent-proxy-example/index.html).

# Matching pkts with RD bit set
The matching function becomes:

    // the only matching we do is on the RD bit
    // for incoming packets.
    func match(m *dns.Msg, d int) (*dns.Msg, bool) {
            // Matching criteria
            var ok bool
            switch d {
            case IN:
                    // only delay pkts with RD bit 
                    ok = m.MsgHdr.RecursionDesired == true
            case OUT:
                    // nothing
            }

            // Packet Mangling
            switch d {
            case IN:
                    // nothing
            case OUT:
                    // nothing
            }
            return m, ok
    }

# Action function
First a delay helper function. As shown here it returns `true` if
the delay time isn't reached, and `false` if a something should be
delayed.

    const NSECDELAY = 1 * 1e9 // 1 second, meaning 1 qps (smaller means higher qps)
    var previous int64 // previous tick

    // returns false if we hit the limit set by NSECDELAY
    func checkDelay() (ti int64, limitok bool) {
            current := time.Nanoseconds()
            tdiff := (current - previous)
            if tdiff < NSECDELAY {
                    // too often
                    return previous, false
            }   
            return current, true
    }


In the action function we check the delay with `checkDelay`, but
only if the match function returned true.
If `checkDelay` returns false, all is OK and we return the packet.
When it returns false we've reached the threshold, so we sleep for
some time and return a `nil` packet.

    func delay(m *dns.Msg, ok bool) *dns.Msg {
            var ok1 bool
            switch ok {
            case true:
                    previous, ok1 = checkDelay()
                    if !ok1 {
                            fmt.Fprintf(os.Stderr, "Info: Dropping: too often")
                            time.Sleep(NSECDELAY)
                            return nil 
                    } else {
                            fmt.Fprintf(os.Stderr, "Info: Dropping: too often")
                            qr[0] <- resolver.Msg{m, nil, nil}
                            in := <-qr[0]
                            return in.Dns
                    }   
            case false:
                    qr[0] <- resolver.Msg{m, nil, nil}
                    in := <-qr[0]
                    return in.Dns
            }   
            return nil 
    }

# Preparing the funkensturm struct

    // Return the configration
    func funkensturm() *Funkensturm {
            f := new(Funkensturm)

            f.Setup = func() bool { previous = time.Nanoseconds(); return true }

            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
    }

[Full source of
config_delay.go](https://github.com/miekg/godns/raw/master/_examples/funkensturm/config_delay.go)

# Trying it!
The following queries are performed in quick succession:

    % dig +short +norec -p 8053 @127.0.0.1 www.example.com
    192.0.32.10

Which works OK and quick, unlike in the
following example, where we fire off queries *with* the
RD bit:

    % dig +short -p 8053 @127.0.0.1 www.example.com
    <quick reply>
    192.0.32.10

    % dig +short -p 8053 @127.0.0.1 www.example.com
    <quick reply>
    192.0.32.10

    % dig +short -p 8053 @127.0.0.1 www.example.com
    <long wait>
    <long wait>
    192.0.32.10

In the terminal where Funkensturm runs, we see:

    Info: Ok: let it through
    Info: Ok: let it through
    Info: Dropping: too often
    Info: Ok: let it through

It works!

