2018-07-06 22:49:21 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								// Package loadbalance shuffles A, AAAA and MX records.
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								package loadbalance
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-04-05 07:37:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									"github.com/miekg/dns"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								)
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-07-06 22:49:21 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								// RoundRobinResponseWriter is a response writer that shuffles A, AAAA and MX records.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								type RoundRobinResponseWriter struct{ dns.ResponseWriter }
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											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)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-11-20 23:38:19 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if res.Question[0].Qtype == dns.TypeAXFR || res.Question[0].Qtype == dns.TypeIXFR {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										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:
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-12 11:00:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										for j := 0; j < l; j++ {
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-15 10:33:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											p := j + (int(dns.Id()) % (l - j))
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-12 11:00:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											if j == p {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												continue
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-12 11:00:20 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											records[j], records[p] = records[p], records[j]
							 | 
						
					
						
							
								
									
										
										
										
											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.
							 | 
						
					
						
							
								
									
										
										
										
											2018-04-19 07:41:56 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									log.Warning("RoundRobin called with Write: not shuffling records")
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-23 15:57:48 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									n, err := r.ResponseWriter.Write(buf)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return n, err
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 |