| 
									
										
										
										
											2016-09-25 08:39:20 +01:00
										 |  |  | // Package loadbalance shuffles A and AAAA records.
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | package loadbalance
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-05 07:37:05 +01:00
										 |  |  | import (
 | 
					
						
							|  |  |  | 	"log"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // RoundRobinResponseWriter is a response writer that shuffles A and AAAA records.
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | type RoundRobinResponseWriter struct {
 | 
					
						
							|  |  |  | 	dns.ResponseWriter
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // WriteMsg implements the dns.ResponseWriter interface.
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | func (r *RoundRobinResponseWriter) WriteMsg(res *dns.Msg) error {
 | 
					
						
							|  |  |  | 	if res.Rcode != dns.RcodeSuccess {
 | 
					
						
							|  |  |  | 		return r.ResponseWriter.WriteMsg(res)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-26 09:53:40 +00:00
										 |  |  | 	res.Answer = roundRobin(res.Answer)
 | 
					
						
							| 
									
										
										
										
											2016-04-05 07:37:05 +01:00
										 |  |  | 	res.Ns = roundRobin(res.Ns)
 | 
					
						
							| 
									
										
										
										
											2016-03-26 09:53:40 +00:00
										 |  |  | 	res.Extra = roundRobin(res.Extra)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return r.ResponseWriter.WriteMsg(res)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func roundRobin(in []dns.RR) []dns.RR {
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 	cname := []dns.RR{}
 | 
					
						
							|  |  |  | 	address := []dns.RR{}
 | 
					
						
							| 
									
										
										
										
											2016-10-27 09:09:16 +02:00
										 |  |  | 	mx := []dns.RR{}
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 	rest := []dns.RR{}
 | 
					
						
							| 
									
										
										
										
											2016-03-26 09:53:40 +00:00
										 |  |  | 	for _, r := range in {
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 		switch r.Header().Rrtype {
 | 
					
						
							|  |  |  | 		case dns.TypeCNAME:
 | 
					
						
							|  |  |  | 			cname = append(cname, r)
 | 
					
						
							|  |  |  | 		case dns.TypeA, dns.TypeAAAA:
 | 
					
						
							|  |  |  | 			address = append(address, r)
 | 
					
						
							| 
									
										
										
										
											2016-10-27 09:09:16 +02:00
										 |  |  | 		case dns.TypeMX:
 | 
					
						
							|  |  |  | 			mx = append(mx, r)
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 		default:
 | 
					
						
							|  |  |  | 			rest = append(rest, r)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 09:09:16 +02:00
										 |  |  | 	roundRobinShuffle(address)
 | 
					
						
							|  |  |  | 	roundRobinShuffle(mx)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	out := append(cname, rest...)
 | 
					
						
							|  |  |  | 	out = append(out, address...)
 | 
					
						
							|  |  |  | 	out = append(out, mx...)
 | 
					
						
							|  |  |  | 	return out
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func roundRobinShuffle(records []dns.RR) {
 | 
					
						
							|  |  |  | 	switch l := len(records); l {
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 	case 0, 1:
 | 
					
						
							| 
									
										
										
										
											2016-03-26 09:53:40 +00:00
										 |  |  | 		break
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 	case 2:
 | 
					
						
							|  |  |  | 		if dns.Id()%2 == 0 {
 | 
					
						
							| 
									
										
										
										
											2016-10-27 09:09:16 +02:00
										 |  |  | 			records[0], records[1] = records[1], records[0]
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 		}
 | 
					
						
							|  |  |  | 	default:
 | 
					
						
							|  |  |  | 		for j := 0; j < l*(int(dns.Id())%4+1); j++ {
 | 
					
						
							|  |  |  | 			q := int(dns.Id()) % l
 | 
					
						
							|  |  |  | 			p := int(dns.Id()) % l
 | 
					
						
							|  |  |  | 			if q == p {
 | 
					
						
							|  |  |  | 				p = (p + 1) % l
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2016-10-27 09:09:16 +02:00
										 |  |  | 			records[q], records[p] = records[p], records[q]
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // Write implements the dns.ResponseWriter interface.
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | func (r *RoundRobinResponseWriter) Write(buf []byte) (int, error) {
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | 	// Should we pack and unpack here to fiddle with the packet... Not likely.
 | 
					
						
							| 
									
										
										
										
											2016-04-05 07:37:05 +01:00
										 |  |  | 	log.Printf("[WARNING] RoundRobin called with Write: no shuffling records")
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | 	n, err := r.ResponseWriter.Write(buf)
 | 
					
						
							|  |  |  | 	return n, err
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // Hijack implements the dns.ResponseWriter interface.
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 |  |  | func (r *RoundRobinResponseWriter) Hijack() {
 | 
					
						
							|  |  |  | 	r.ResponseWriter.Hijack()
 | 
					
						
							|  |  |  | 	return
 | 
					
						
							|  |  |  | }
 |