Skip to content

Commit 587de6a

Browse files
added dns parsing but in leaky manner
1 parent 6831fda commit 587de6a

File tree

5 files changed

+261
-25
lines changed

5 files changed

+261
-25
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ Check proxy logs for traffic from other devices from your LAN
528528
529529
### UDP support
530530
531-
`GoHPTS` has UDP support that can be enabled in `tproxy` mode. For this setup to work you need to connect to a socks5 server capable of serving UDP connections (`UDP ASSOCIATE`). For example, you can use [https://github.com/wzshiming/socks5](https://github.com/wzshiming/socks5) to deploy UDP capable UDP server on some remote or local machine. Once you have the server to connect to, run the following command:
531+
`GoHPTS` has UDP support that can be enabled in `tproxy` mode. For this setup to work you need to connect to a socks5 server capable of serving UDP connections (`UDP ASSOCIATE`). For example, you can use [https://github.com/wzshiming/socks5](https://github.com/wzshiming/socks5) to deploy UDP capable socks5 server on some remote or local machine. Once you have the server to connect to, run the following command:
532532
533533
```shell
534534
sudo env PATH=$PATH gohpts -s remote -Tu :8989 -M tproxy -auto -mark 100 -d
@@ -539,7 +539,7 @@ This command will configure your operating system and setup server on `0.0.0.0:8
539539
To test it locally, you can combine UDP transparent proxy with `-arpspoof` flag. For example:
540540
541541
1. Setup VM on your system with any Linux distributive that supports `tproxy` (Kali Linux, for instance).
542-
2. Enable `Bridged` network so that VM could access your host machine.
542+
2. Enable `bridged` network so that VM could access your host machine.
543543
3. Move `gohpts` binary to VM (via `ssh`, for instance) or build it there in case of different OS/arch.
544544
4. On your VM run the following command:
545545

colorize.go

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ var (
2121
`(?:\[(?:[0-9a-fA-F:.]+)\]|(?:\d{1,3}\.){3}\d{1,3})(?::(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4}))?`,
2222
)
2323
domainPattern = regexp.MustCompile(
24-
`\b(?:[a-zA-Z0-9-]{1,63}\.)+(?:com|net|org|io|co|uk|ru|de|edu|gov|info|biz|dev|app|ai)(?::(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4}))?\b`,
24+
`\b(?:[a-zA-Z0-9-]{1,63}\.)+(?:com|net|org|io|co|uk|ru|de|edu|gov|info|biz|dev|app|ai|tv)(?::(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4}))?\b`,
2525
)
2626
jwtPattern = regexp.MustCompile(`\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b`)
2727
authPattern = regexp.MustCompile(
@@ -187,9 +187,9 @@ func colorizeHTTP(
187187

188188
func colorizeTLS(req *layers.TLSClientHello, resp *layers.TLSServerHello, id string, nocolor bool) string {
189189
var sb strings.Builder
190+
sb.WriteString(fmt.Sprintf("%s ", colorizeTimestamp(time.Now(), nocolor)))
191+
sb.WriteString(id)
190192
if nocolor {
191-
sb.WriteString(fmt.Sprintf("%s ", colorizeTimestamp(time.Now(), nocolor)))
192-
sb.WriteString(id)
193193
sb.WriteString(fmt.Sprintf(" %s ", req.TypeDesc))
194194
if req.Length > 0 {
195195
sb.WriteString(fmt.Sprintf(" Len: %d", req.Length))
@@ -224,8 +224,6 @@ func colorizeTLS(req *layers.TLSClientHello, resp *layers.TLSServerHello, id str
224224
sb.WriteString(fmt.Sprintf(" ExtLen: %d", resp.ExtensionLength))
225225
}
226226
} else {
227-
sb.WriteString(fmt.Sprintf("%s ", colorizeTimestamp(time.Now(), nocolor)))
228-
sb.WriteString(id)
229227
sb.WriteString(colors.Magenta(fmt.Sprintf(" %s ", req.TypeDesc)).Bold())
230228
if req.Length > 0 {
231229
sb.WriteString(colors.BeigeBg(fmt.Sprintf(" Len: %d", req.Length)).String())
@@ -263,6 +261,98 @@ func colorizeTLS(req *layers.TLSClientHello, resp *layers.TLSServerHello, id str
263261
return sb.String()
264262
}
265263

264+
func colorizeRData(rec *layers.ResourceRecord) string {
265+
var rdata string
266+
switch rd := rec.RData.(type) {
267+
case *layers.RDataA:
268+
case *layers.RDataAAAA:
269+
rdata = fmt.Sprintf("%s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(rd.Address.String()))
270+
case *layers.RDataNS:
271+
rdata = fmt.Sprintf("%s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(rd.NsdName))
272+
case *layers.RDataCNAME:
273+
rdata = fmt.Sprintf("%s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(rd.CName))
274+
case *layers.RDataSOA:
275+
rdata = fmt.Sprintf("%s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(rd.PrimaryNS))
276+
case *layers.RDataMX:
277+
rdata = fmt.Sprintf("%s %s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(fmt.Sprintf("%d", rd.Preference)), colors.Gray(rd.Exchange))
278+
case *layers.RDataTXT:
279+
rdata = fmt.Sprintf("%s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(rd.TxtData))
280+
default:
281+
rdata = fmt.Sprintf("%s ", colors.LightBlue(rec.Type.Name))
282+
}
283+
return rdata
284+
}
285+
286+
func colorizeDNS(req, resp *layers.DNSMessage, id string, nocolor bool) string {
287+
var sb strings.Builder
288+
sb.WriteString(fmt.Sprintf("%s ", colorizeTimestamp(time.Now(), nocolor)))
289+
sb.WriteString(id)
290+
if nocolor {
291+
sb.WriteString(fmt.Sprintf(" DNS %s (%s) %#04x ", req.Flags.OPCodeDesc, req.Flags.QRDesc, req.TransactionID))
292+
for _, rec := range req.Questions {
293+
sb.WriteString(fmt.Sprintf("%s %s ", rec.Type.Name, rec.Name))
294+
}
295+
for _, rec := range req.AnswerRRs {
296+
sb.WriteString(rec.Summary())
297+
}
298+
for _, rec := range req.AuthorityRRs {
299+
sb.WriteString(rec.Summary())
300+
}
301+
for _, rec := range req.AdditionalRRs {
302+
sb.WriteString(rec.Summary())
303+
}
304+
sb.WriteString("\n")
305+
sb.WriteString(fmt.Sprintf("%s ", colorizeTimestamp(time.Now(), nocolor)))
306+
sb.WriteString(id)
307+
sb.WriteString(fmt.Sprintf(" DNS %s (%s) %#04x ", resp.Flags.OPCodeDesc, resp.Flags.QRDesc, resp.TransactionID))
308+
for _, rec := range resp.Questions {
309+
sb.WriteString(fmt.Sprintf("%s %s ", rec.Type.Name, rec.Name))
310+
}
311+
for _, rec := range resp.AnswerRRs {
312+
sb.WriteString(rec.Summary())
313+
}
314+
for _, rec := range resp.AuthorityRRs {
315+
sb.WriteString(rec.Summary())
316+
}
317+
for _, rec := range resp.AdditionalRRs {
318+
sb.WriteString(rec.Summary())
319+
}
320+
} else {
321+
sb.WriteString(colors.Gray(fmt.Sprintf(" DNS %s (%s)", req.Flags.OPCodeDesc, req.Flags.QRDesc)).Bold())
322+
sb.WriteString(colors.Beige(fmt.Sprintf(" %#04x ", req.TransactionID)).String())
323+
for _, rec := range req.Questions {
324+
sb.WriteString(fmt.Sprintf("%s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(rec.Name)))
325+
}
326+
for _, rec := range req.AnswerRRs {
327+
sb.WriteString(colorizeRData(rec))
328+
}
329+
for _, rec := range req.AuthorityRRs {
330+
sb.WriteString(colorizeRData(rec))
331+
}
332+
for _, rec := range req.AdditionalRRs {
333+
sb.WriteString(colorizeRData(rec))
334+
}
335+
sb.WriteString("\n")
336+
sb.WriteString(fmt.Sprintf("%s ", colorizeTimestamp(time.Now(), nocolor)))
337+
sb.WriteString(id)
338+
sb.WriteString(colors.Blue(fmt.Sprintf(" DNS %s (%s)", resp.Flags.OPCodeDesc, resp.Flags.QRDesc)).Bold())
339+
sb.WriteString(colors.Beige(fmt.Sprintf(" %#04x ", resp.TransactionID)).String())
340+
for _, rec := range resp.Questions {
341+
sb.WriteString(fmt.Sprintf("%s %s ", colors.LightBlue(rec.Type.Name), colors.Gray(rec.Name)))
342+
}
343+
for _, rec := range resp.AnswerRRs {
344+
sb.WriteString(colorizeRData(rec))
345+
}
346+
for _, rec := range resp.AuthorityRRs {
347+
sb.WriteString(colorizeRData(rec))
348+
}
349+
for _, rec := range resp.AdditionalRRs {
350+
sb.WriteString(colorizeRData(rec))
351+
}
352+
}
353+
return sb.String()
354+
}
355+
266356
func highlightPatterns(line string, nocolor bool) (string, bool) {
267357
matched := false
268358

@@ -377,7 +467,7 @@ func colorizeConnections(srcRemote, srcLocal, dstRemote, dstLocal net.Addr, id s
377467
}
378468

379469
func colorizeConnectionsTransparent(
380-
srcRemote, srcLocal, dstRemote, dstLocal net.Addr,
470+
srcRemote, srcLocal, dstLocal, dstRemote net.Addr,
381471
dst,
382472
id string,
383473
nocolor bool,

gohpts.go

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ func New(conf *Config) *proxyapp {
288288
p.logger.Fatal().Err(err).Msg("")
289289
}
290290
}
291+
if network.AddrEqual(p.tproxyAddr, p.tproxyAddrUDP) {
292+
p.logger.Fatal().Msgf("%s: address already in use", p.tproxyAddrUDP)
293+
}
291294
p.auto = conf.Auto
292295
if p.auto && runtime.GOOS != "linux" {
293296
p.logger.Fatal().Msg("Auto setup is available only on linux systems")
@@ -690,7 +693,6 @@ func (p *proxyapp) handleForward(w http.ResponseWriter, r *http.Request) {
690693
var resp *http.Response
691694
var chunked bool
692695
var respBodySaved []byte
693-
p.httpClient.Timeout = timeout
694696
if network.IsLocalAddress(r.Host) {
695697
resp = p.doReq(w, req, nil)
696698
} else {
@@ -879,7 +881,7 @@ func (p *proxyapp) handleTunnel(w http.ResponseWriter, r *http.Request) {
879881
if p.json {
880882
sniffdata = append(
881883
sniffdata,
882-
fmt.Sprintf("{\"connection\":{\"src_remote\":%s,\"src_local\":%s,\"dst_local\":%s,\"dst_remote\":%s}}",
884+
fmt.Sprintf("{\"connection\":{\"src_remote\":%q,\"src_local\":%q,\"dst_local\":%q,\"dst_remote\":%q}}",
883885
srcConn.RemoteAddr(), srcConn.LocalAddr(), dstConn.LocalAddr(), dstConn.RemoteAddr()),
884886
)
885887
j, err := json.Marshal(&layers.HTTPMessage{Request: r})
@@ -1205,14 +1207,29 @@ func (p *proxyapp) gatherSniffData(req, resp layers.Layer, sniffdata *[]string,
12051207
*sniffdata = append(*sniffdata, colorizeTLS(chs, shs, id, p.nocolor))
12061208
}
12071209
}
1210+
case *layers.DNSMessage:
1211+
rest := resp.(*layers.DNSMessage)
1212+
if p.json {
1213+
j1, err := json.Marshal(reqt)
1214+
if err != nil {
1215+
return err
1216+
}
1217+
j2, err := json.Marshal(rest)
1218+
if err != nil {
1219+
return err
1220+
}
1221+
*sniffdata = append(*sniffdata, string(j1), string(j2))
1222+
} else {
1223+
*sniffdata = append(*sniffdata, colorizeDNS(reqt, rest, id, p.nocolor))
1224+
}
12081225
}
12091226
return nil
12101227
}
12111228

12121229
func (p *proxyapp) sniffreporter(wg *sync.WaitGroup, sniffdata *[]string, reqChan, respChan <-chan layers.Layer, id string) {
12131230
defer wg.Done()
12141231
sniffdatalen := len(*sniffdata)
1215-
var reqTLSQueue, respTLSQueue, reqHTTPQueue, respHTTPQueue []layers.Layer
1232+
var reqTLSQueue, respTLSQueue, reqHTTPQueue, respHTTPQueue, reqDNSQueue, respDNSQueue []layers.Layer
12161233
for {
12171234
select {
12181235
case req, ok := <-reqChan:
@@ -1224,6 +1241,8 @@ func (p *proxyapp) sniffreporter(wg *sync.WaitGroup, sniffdata *[]string, reqCha
12241241
reqTLSQueue = append(reqTLSQueue, req)
12251242
case *layers.HTTPMessage:
12261243
reqHTTPQueue = append(reqHTTPQueue, req)
1244+
case *layers.DNSMessage:
1245+
reqDNSQueue = append(reqDNSQueue, req)
12271246
}
12281247
}
12291248
case resp, ok := <-respChan:
@@ -1245,6 +1264,12 @@ func (p *proxyapp) sniffreporter(wg *sync.WaitGroup, sniffdata *[]string, reqCha
12451264
} else if len(reqHTTPQueue) == 0 && len(respHTTPQueue) == 1 {
12461265
respHTTPQueue = respHTTPQueue[1:]
12471266
}
1267+
case *layers.DNSMessage:
1268+
if len(reqDNSQueue) > 0 || len(respDNSQueue) == 0 {
1269+
respDNSQueue = append(respDNSQueue, resp)
1270+
} else if len(reqDNSQueue) == 0 && len(respDNSQueue) == 1 {
1271+
respDNSQueue = respDNSQueue[1:]
1272+
}
12481273
}
12491274
}
12501275
}
@@ -1270,6 +1295,22 @@ func (p *proxyapp) sniffreporter(wg *sync.WaitGroup, sniffdata *[]string, reqCha
12701295
reqTLSQueue = reqTLSQueue[1:]
12711296
respTLSQueue = respTLSQueue[1:]
12721297

1298+
err := p.gatherSniffData(req, resp, sniffdata, id)
1299+
if err == nil && len(*sniffdata) > sniffdatalen {
1300+
if p.json {
1301+
p.snifflogger.Log().Msg(fmt.Sprintf("[%s]", strings.Join(*sniffdata, ",")))
1302+
} else {
1303+
p.snifflogger.Log().Msg(strings.Join(*sniffdata, "\n"))
1304+
}
1305+
}
1306+
*sniffdata = (*sniffdata)[:sniffdatalen]
1307+
}
1308+
if len(reqDNSQueue) > 0 && len(respDNSQueue) > 0 {
1309+
req := reqDNSQueue[0]
1310+
resp := respDNSQueue[0]
1311+
reqDNSQueue = reqDNSQueue[1:]
1312+
respDNSQueue = respDNSQueue[1:]
1313+
12731314
err := p.gatherSniffData(req, resp, sniffdata, id)
12741315
if err == nil && len(*sniffdata) > sniffdatalen {
12751316
if p.json {

tproxy_linux.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ func (ts *tproxyServer) handleConnection(srcConn net.Conn) {
198198
sniffheader = append(
199199
sniffheader,
200200
fmt.Sprintf(
201-
"{\"connection\":{\"tproxy_mode\":%s,\"src_remote\":%s,\"src_local\":%s,\"dst_local\":%s,\"dst_remote\":%s,\"original_dst\":%s}}",
201+
"{\"connection\":{\"tproxy_mode\":%q,\"src_remote\":%q,\"src_local\":%q,\"dst_local\":%q,\"dst_remote\":%q,\"original_dst\":%q}}",
202202
ts.p.tproxyMode,
203203
srcConn.RemoteAddr(),
204204
srcConn.LocalAddr(),
@@ -211,8 +211,8 @@ func (ts *tproxyServer) handleConnection(srcConn net.Conn) {
211211
connections := colorizeConnectionsTransparent(
212212
srcConn.RemoteAddr(),
213213
srcConn.LocalAddr(),
214-
dstConn.RemoteAddr(),
215214
dstConn.LocalAddr(),
215+
dstConn.RemoteAddr(),
216216
dst, id, ts.p.nocolor)
217217
sniffheader = append(sniffheader, connections)
218218
}

0 commit comments

Comments
 (0)