mirror of
				https://github.com/maride/pancap.git
				synced 2025-10-10 19:36:51 +00:00 
			
		
		
		
	Add support for HTTP packets
This commit is contained in:
		
							parent
							
								
									56b493283e
								
							
						
					
					
						commit
						cd01dc7664
					
				
							
								
								
									
										52
									
								
								protocol/http/http.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								protocol/http/http.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| package http | ||||
| 
 | ||||
| import ( | ||||
| 	"git.darknebu.la/maride/pancap/common" | ||||
| 	"git.darknebu.la/maride/pancap/output" | ||||
| 	"github.com/google/gopacket" | ||||
| 	"github.com/google/gopacket/layers" | ||||
| 	"github.com/google/gopacket/tcpassembly" | ||||
| ) | ||||
| 
 | ||||
| type Protocol struct { | ||||
| 	initialized bool | ||||
| 	requestFactory *httpRequestFactory | ||||
| 	responseFactory *httpResponseFactory | ||||
| 	requestPool *tcpassembly.StreamPool | ||||
| 	responsePool *tcpassembly.StreamPool | ||||
| 	requestAssembler *tcpassembly.Assembler | ||||
| 	responseAssembler *tcpassembly.Assembler | ||||
| } | ||||
| 
 | ||||
| // Checks if the given packet is an HTTP packet we can process | ||||
| func (p *Protocol) CanAnalyze(packet gopacket.Packet) bool { | ||||
| 	return packet.Layer(layers.LayerTypeTCP) != nil && packet.Layer(layers.LayerTypeTLS) == nil | ||||
| } | ||||
| 
 | ||||
| // Analyzes the given HTTP packet | ||||
| func (p *Protocol) Analyze(packet gopacket.Packet) error { | ||||
| 	// Check if we need to init | ||||
| 	if !p.initialized { | ||||
| 		// Initialize | ||||
| 		p.requestFactory = &httpRequestFactory{} | ||||
| 		p.responseFactory = &httpResponseFactory{} | ||||
| 		p.requestPool = tcpassembly.NewStreamPool(p.requestFactory) | ||||
| 		p.responsePool = tcpassembly.NewStreamPool(p.responseFactory) | ||||
| 		p.requestAssembler = tcpassembly.NewAssembler(p.requestPool) | ||||
| 		p.responseAssembler = tcpassembly.NewAssembler(p.responsePool) | ||||
| 		p.initialized = true | ||||
| 	} | ||||
| 
 | ||||
| 	// Try to cast packet and assemble HTTP stream | ||||
| 	tcp := packet.TransportLayer().(*layers.TCP) | ||||
| 	p.requestAssembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) | ||||
| 	p.responseAssembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Print a summary after all packets are processed | ||||
| func (p *Protocol) PrintSummary() { | ||||
| 	output.PrintBlock("HTTP Requests", common.GenerateTree(requestSummaryLines)) | ||||
| 	output.PrintBlock("HTTP Responses", common.GenerateTree(responseSummaryLines)) | ||||
| } | ||||
							
								
								
									
										67
									
								
								protocol/http/httpRequestFactory.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								protocol/http/httpRequestFactory.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| package http | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"github.com/google/gopacket" | ||||
| 	"github.com/google/gopacket/tcpassembly" | ||||
| 	"github.com/google/gopacket/tcpassembly/tcpreader" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	requestSummaryLines []string | ||||
| ) | ||||
| 
 | ||||
| type httpRequestFactory struct{} | ||||
| 
 | ||||
| type httpRequestStream struct { | ||||
| 	net, transport gopacket.Flow | ||||
| 	r              tcpreader.ReaderStream | ||||
| } | ||||
| 
 | ||||
| // Creates a new HTTPRequestStream for the given packet flow, and analyzes it in a separate thread | ||||
| func (h *httpRequestFactory) New(net, transport gopacket.Flow) tcpassembly.Stream { | ||||
| 	hstream := &httpRequestStream{ | ||||
| 		net:       net, | ||||
| 		transport: transport, | ||||
| 		r:         tcpreader.NewReaderStream(), | ||||
| 	} | ||||
| 
 | ||||
| 	// Start analyzer as thread and return TCP reader stream | ||||
| 	go hstream.run() | ||||
| 	return &hstream.r | ||||
| } | ||||
| 
 | ||||
| // Analyzes the given request | ||||
| func (h *httpRequestStream) run() { | ||||
| 	iobuf := bufio.NewReader(&h.r) | ||||
| 
 | ||||
| 	for { | ||||
| 		req, reqErr := http.ReadRequest(iobuf) | ||||
| 
 | ||||
| 		if reqErr == io.EOF { | ||||
| 			// That's ok, we can ignore EOF errors | ||||
| 			return | ||||
| 		} else if reqErr != nil { | ||||
| 			// Ignore, because it may be a response | ||||
| 		} else { | ||||
| 			// Try to process assembled request | ||||
| 			tcpreader.DiscardBytesToEOF(req.Body) | ||||
| 			req.Body.Close() | ||||
| 
 | ||||
| 			// Build summary | ||||
| 			line := fmt.Sprintf("Request %s http://%s%s", req.Method, req.Host, req.RequestURI) | ||||
| 			requestSummaryLines = append(requestSummaryLines, line) | ||||
| 
 | ||||
| 			// Check for file uploads | ||||
| 			if req.MultipartForm != nil && req.MultipartForm.File != nil { | ||||
| 				for k, v := range req.MultipartForm.File { | ||||
| 					log.Println(k, v) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										59
									
								
								protocol/http/httpResponseFactory.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								protocol/http/httpResponseFactory.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| package http | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"github.com/google/gopacket" | ||||
| 	"github.com/google/gopacket/tcpassembly" | ||||
| 	"github.com/google/gopacket/tcpassembly/tcpreader" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	responseSummaryLines   []string | ||||
| ) | ||||
| 
 | ||||
| type httpResponseFactory struct{} | ||||
| 
 | ||||
| type httpResponseStream struct { | ||||
| 	net, transport gopacket.Flow | ||||
| 	r              tcpreader.ReaderStream | ||||
| } | ||||
| 
 | ||||
| // Creates a new HTTPResponseStream for the given packet flow, and analyzes it in a separate thread | ||||
| func (h *httpResponseFactory) New(net, transport gopacket.Flow) tcpassembly.Stream { | ||||
| 	hstream := &httpResponseStream{ | ||||
| 		net:       net, | ||||
| 		transport: transport, | ||||
| 		r:         tcpreader.NewReaderStream(), | ||||
| 	} | ||||
| 	go hstream.run() // Important... we must guarantee that data from the reader stream is read. | ||||
| 
 | ||||
| 	// ReaderStream implements tcpassembly.Stream, so we can return a pointer to it. | ||||
| 	return &hstream.r | ||||
| } | ||||
| 
 | ||||
| // Analyzes the given response | ||||
| func (h *httpResponseStream) run() { | ||||
| 	iobuf := bufio.NewReader(&h.r) | ||||
| 
 | ||||
| 	for { | ||||
| 		resp, respErr := http.ReadResponse(iobuf, nil) | ||||
| 
 | ||||
| 		if respErr == io.EOF { | ||||
| 			// That's ok, we can ignore EOF errors | ||||
| 			return | ||||
| 		} else if respErr != nil { | ||||
| 			// Ignore, because it may be a request | ||||
| 		} else { | ||||
| 			// Try to process assembled request | ||||
| 			tcpreader.DiscardBytesToEOF(resp.Body) | ||||
| 			resp.Body.Close() | ||||
| 
 | ||||
| 			// Build summary | ||||
| 			line := fmt.Sprintf("Response %s, Type %s, Size %d bytes", resp.Status, resp.Header.Get("Content-Type"), resp.ContentLength) | ||||
| 			responseSummaryLines = append(responseSummaryLines, line) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -4,6 +4,7 @@ import ( | ||||
| 	"git.darknebu.la/maride/pancap/protocol/arp" | ||||
| 	"git.darknebu.la/maride/pancap/protocol/dhcpv4" | ||||
| 	"git.darknebu.la/maride/pancap/protocol/dns" | ||||
| 	"git.darknebu.la/maride/pancap/protocol/http" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| @ -11,5 +12,6 @@ var ( | ||||
| 		&arp.Protocol{}, | ||||
| 		&dhcpv4.Protocol{}, | ||||
| 		&dns.Protocol{}, | ||||
| 		&http.Protocol{}, | ||||
| 	} | ||||
| ) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user