| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | // Package errors implements an HTTP error handling middleware.
 | 
					
						
							|  |  |  | package errors
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							|  |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 	"log"
 | 
					
						
							|  |  |  | 	"runtime"
 | 
					
						
							|  |  |  | 	"strings"
 | 
					
						
							|  |  |  | 	"time"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 22:51:47 -08:00
										 |  |  | 	"github.com/coredns/coredns/middleware"
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/request"
 | 
					
						
							| 
									
										
										
										
											2016-04-11 07:56:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 	"github.com/miekg/dns"
 | 
					
						
							| 
									
										
										
										
											2016-04-11 07:56:38 +01:00
										 |  |  | 	"golang.org/x/net/context"
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // errorHandler handles DNS errors (and errors from other middleware).
 | 
					
						
							|  |  |  | type errorHandler struct {
 | 
					
						
							| 
									
										
										
										
											2016-09-16 07:50:16 -07:00
										 |  |  | 	Next    middleware.Handler
 | 
					
						
							|  |  |  | 	LogFile string
 | 
					
						
							|  |  |  | 	Log     *log.Logger
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // ServeDNS implements the middleware.Handler interface.
 | 
					
						
							|  |  |  | func (h errorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
 | 
					
						
							| 
									
										
										
										
											2016-03-19 12:58:08 +00:00
										 |  |  | 	defer h.recovery(ctx, w, r)
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-20 18:58:05 +00:00
										 |  |  | 	rcode, err := middleware.NextOrFailure(h.Name(), h.Next, ctx, w, r)
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | 		state := request.Request{W: w, Req: r}
 | 
					
						
							| 
									
										
										
										
											2016-03-19 12:58:08 +00:00
										 |  |  | 		errMsg := fmt.Sprintf("%s [ERROR %d %s %s] %v", time.Now().Format(timeFormat), rcode, state.Name(), state.Type(), err)
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		h.Log.Println(errMsg)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return rcode, err
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 10:01:52 +01:00
										 |  |  | func (h errorHandler) Name() string { return "errors" }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | func (h errorHandler) recovery(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) {
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 	rec := recover()
 | 
					
						
							|  |  |  | 	if rec == nil {
 | 
					
						
							|  |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Obtain source of panic
 | 
					
						
							|  |  |  | 	// From: https://gist.github.com/swdunlop/9629168
 | 
					
						
							|  |  |  | 	var name, file string // function name, file name
 | 
					
						
							|  |  |  | 	var line int
 | 
					
						
							|  |  |  | 	var pc [16]uintptr
 | 
					
						
							|  |  |  | 	n := runtime.Callers(3, pc[:])
 | 
					
						
							|  |  |  | 	for _, pc := range pc[:n] {
 | 
					
						
							|  |  |  | 		fn := runtime.FuncForPC(pc)
 | 
					
						
							|  |  |  | 		if fn == nil {
 | 
					
						
							|  |  |  | 			continue
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		file, line = fn.FileLine(pc)
 | 
					
						
							|  |  |  | 		name = fn.Name()
 | 
					
						
							|  |  |  | 		if !strings.HasPrefix(name, "runtime.") {
 | 
					
						
							|  |  |  | 			break
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Trim file path
 | 
					
						
							|  |  |  | 	delim := "/coredns/"
 | 
					
						
							|  |  |  | 	pkgPathPos := strings.Index(file, delim)
 | 
					
						
							|  |  |  | 	if pkgPathPos > -1 && len(file) > pkgPathPos+len(delim) {
 | 
					
						
							|  |  |  | 		file = file[pkgPathPos+len(delim):]
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	panicMsg := fmt.Sprintf("%s [PANIC %s %s] %s:%d - %v", time.Now().Format(timeFormat), r.Question[0].Name, dns.Type(r.Question[0].Qtype), file, line, rec)
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:28:53 +01:00
										 |  |  | 	// Currently we don't use the function name, since file:line is more conventional
 | 
					
						
							|  |  |  | 	h.Log.Printf(panicMsg)
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const timeFormat = "02/Jan/2006:15:04:05 -0700"
 |