Skip to content

Commit 606ebc2

Browse files
added packet queue to fix possible packet losses
1 parent 6bd1628 commit 606ebc2

File tree

3 files changed

+56
-24
lines changed

3 files changed

+56
-24
lines changed

README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
![mshark_new](https://github.com/user-attachments/assets/ee1b9526-dcae-4ff8-962d-315897e49ed0)
2+
23
# mShark - Mini [Wireshark](https://www.wireshark.org/) written in Go
34

45
[![Go Reference](https://pkg.go.dev/badge/github.com/shadowy-pycoder/mshark.svg)](https://pkg.go.dev/github.com/shadowy-pycoder/mshark)
@@ -8,7 +9,6 @@
89
![GitHub Release](https://img.shields.io/github/v/release/shadowy-pycoder/mshark)
910
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/shadowy-pycoder/mshark/total)
1011

11-
1212
## Installation
1313

1414
Download release from [Releases](https://github.com/shadowy-pycoder/mshark/releases) Page.
@@ -18,9 +18,11 @@ Or install using `go install` (requires Go 1.23+ but may work with older version
1818
```shell
1919
CGO_ENABLED=0 go install -ldflags "-s -w" -trimpath github.com/shadowy-pycoder/mshark/cmd/mshark@latest
2020
```
21+
2122
This will install the `mshark` binary to your `$GOPATH/bin` directory.
2223

23-
If you are getting a `Permission denied` error when running `mshark`, try running
24+
If you are getting a `Permission denied` error when running `mshark`, try running
25+
2426
```shell
2527
sudo setcap cap_net_raw+ep ~/go/bin/mshark
2628
```
@@ -30,24 +32,26 @@ sudo setcap cap_net_raw+ep ~/go/bin/mshark
3032
```shell
3133
mshark -h
3234

33-
______ __ __
34-
/ \ | \ | \
35-
______ ____ | $$$$$$\| $$____ ______ ______ | $$ __
35+
______ __ __
36+
/ \ | \ | \
37+
______ ____ | $$$$$$\| $$____ ______ ______ | $$ __
3638
| \ \ | $$___\$$| $$ \ | \ / \ | $$ / \
3739
| $$$$$$\$$$$\ \$$ \ | $$$$$$$\ \$$$$$$\| $$$$$$\| $$_/ $$
38-
| $$ | $$ | $$ _\$$$$$$\| $$ | $$ / $$| $$ \$$| $$ $$
39-
| $$ | $$ | $$| \__| $$| $$ | $$| $$$$$$$| $$ | $$$$$$\
40+
| $$ | $$ | $$ _\$$$$$$\| $$ | $$ / $$| $$ \$$| $$ $$
41+
| $$ | $$ | $$| \__| $$| $$ | $$| $$$$$$$| $$ | $$$$$$\
4042
| $$ | $$ | $$ \$$ $$| $$ | $$ \$$ $$| $$ | $$ \$$\
4143
\$$ \$$ \$$ \$$$$$$ \$$ \$$ \$$$$$$$ \$$ \$$ \$$
42-
43-
Packet Capture Tool by shadowy-pycoder
44+
45+
Packet Capture Tool by shadowy-pycoder
4446

4547
GitHub: https://github.com/shadowy-pycoder/mshark
4648

4749
Usage: mshark [OPTIONS]
4850
Options:
4951
-h Show this help message and exit.
5052
-D Display list of interfaces and exit.
53+
-b int
54+
The maximum size of packet queue. (default 4096)
5155
-c int
5256
The maximum number of packets to capture.
5357
-e string
@@ -62,13 +66,14 @@ Options:
6266
-t duration
6367
The maximum duration of the packet capture process. Example: 5s
6468
-v Display full packet info when capturing to stdout or txt.
65-
```
69+
```
6670

6771
### Example
6872

6973
```shell
7074
mshark -p -f=txt -f=stdout -f=pcapng -i eth0 -e="port 53"
7175
```
76+
7277
The above command will capture packets containing `port 53` (assumed to be DNS queries) from the `eth0` interface and write the captured data to `stdout`, `txt`, and file in `pcapng` format. Files are created in the current working directory.
7378

7479
Output:
@@ -79,20 +84,21 @@ Output:
7984
- Promiscuous Mode: true
8085
- Timeout: 0s
8186
- Number of Packets: 0
87+
- Packet Buffer Size: 4096
8288
- BPF Filter: "port 53"
8389
- Verbose: false
8490
```
91+
8592
![Screenshot from 2024-09-17 09-37-50](https://github.com/user-attachments/assets/44c233ee-85a4-43f2-8f65-1ef239362bab)
8693

8794
With `-v` flag enabled, you will see more detailed information:
8895

89-
9096
![Screenshot from 2024-09-17 09-56-20](https://github.com/user-attachments/assets/11539ea7-779e-4faf-8fce-2eea9ab653c7)
9197
![Screenshot from 2024-09-17 09-56-47](https://github.com/user-attachments/assets/26b6353d-d312-40c5-9917-3f2f7bb8abdc)
9298

9399
## Supported layers
94100

95-
- [Ethernet](https://en.wikipedia.org/wiki/Ethernet_frame)
101+
- [Ethernet](https://en.wikipedia.org/wiki/Ethernet_frame)
96102
- [IPv4](https://en.wikipedia.org/wiki/IPv4)
97103
- [IPv6](https://en.wikipedia.org/wiki/IPv6)
98104
- [ARP](https://en.wikipedia.org/wiki/Address_Resolution_Protocol)
@@ -107,7 +113,6 @@ With `-v` flag enabled, you will see more detailed information:
107113
- [SSH](https://en.wikipedia.org/wiki/Secure_Shell)
108114
- [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security)
109115

110-
111116
## Roadmap
112117

113118
- [x] Online packet capture to `stdout`, `txt`, `pcap` and `pcapng` files

cmd/mshark/cli.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ func root(args []string) error {
102102
)
103103
flags.DurationVar(&conf.Timeout, "t", 0, "The maximum duration of the packet capture process. Example: 5s")
104104
flags.IntVar(&conf.PacketCount, "c", 0, "The maximum number of packets to capture.")
105+
packetBuffer := flags.Int("b", 4096, "The maximum size of packet queue.")
105106
flags.StringVar(&conf.Expr, "e", "", `BPF filter expression. Example: "ip proto tcp".`)
106107
flags.BoolFunc("D", "Display list of interfaces and exit.", func(flagValue string) error {
107108
if err := displayInterfaces(); err != nil {
@@ -141,6 +142,11 @@ func root(args []string) error {
141142
}
142143
conf.Snaplen = *snaplen
143144

145+
if *packetBuffer <= 0 {
146+
*packetBuffer = 4096
147+
}
148+
conf.PacketBuffer = *packetBuffer
149+
144150
// creating writers and writing headers depending on a file extension
145151
var pw []ms.PacketWriter
146152
if len(exts) != 0 {

mshark.go

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ type PacketWriter interface {
3333
}
3434

3535
type Config struct {
36-
Device *net.Interface // The name of the network interface ("any" means listen on all interfaces).
37-
Snaplen int // The maximum length of each packet snapshot.
38-
Promisc bool // Promiscuous mode. This setting is ignored for "any" interface.
39-
Timeout time.Duration // The maximum duration of the packet capture process.
40-
PacketCount int // The maximum number of packets to capture.
41-
Expr string // BPF filter expression.
36+
Device *net.Interface // The name of the network interface ("any" means listen on all interfaces).
37+
Snaplen int // The maximum length of each packet snapshot.
38+
Promisc bool // Promiscuous mode. This setting is ignored for "any" interface.
39+
Timeout time.Duration // The maximum duration of the packet capture process.
40+
PacketCount int // The maximum number of packets to capture.
41+
PacketBuffer int // The maximum size for packet buffer (Default: 4096)
42+
Expr string // BPF filter expression.
4243
}
4344

4445
type Writer struct {
@@ -121,6 +122,7 @@ func (mw *Writer) WriteHeader(c *Config) error {
121122
- Promiscuous Mode: %v
122123
- Timeout: %s
123124
- Number of Packets: %d
125+
- Packet Buffer Size: %d
124126
- BPF Filter: %q
125127
- Verbose: %v
126128
@@ -130,6 +132,7 @@ func (mw *Writer) WriteHeader(c *Config) error {
130132
c.Device.Name != "any" && c.Promisc,
131133
c.Timeout,
132134
c.PacketCount,
135+
c.PacketBuffer,
133136
c.Expr,
134137
mw.verbose,
135138
)
@@ -239,10 +242,31 @@ func OpenLive(conf *Config, pw ...PacketWriter) error {
239242
infinity := count == 0
240243

241244
b := make([]byte, conf.Snaplen)
245+
if conf.PacketBuffer <= 0 {
246+
conf.PacketBuffer = 4096
247+
}
248+
packetQueue := make(chan []byte, conf.PacketBuffer)
249+
250+
go func() {
251+
for {
252+
select {
253+
case <-done:
254+
return
255+
case packet, ok := <-packetQueue:
256+
if !ok {
257+
return
258+
}
259+
for _, w := range pw {
260+
w.WritePacket(time.Now().UTC(), packet)
261+
}
262+
}
263+
}
264+
}()
242265

243266
for i := 0; infinity || i < count; i++ {
244267
select {
245268
case <-done:
269+
close(packetQueue)
246270
return nil
247271
default:
248272
n, _, err := c.ReadFrom(b)
@@ -252,11 +276,8 @@ func OpenLive(conf *Config, pw ...PacketWriter) error {
252276
}
253277
return fmt.Errorf("failed to read Ethernet frame: %v", err)
254278
}
255-
for _, w := range pw {
256-
if err := w.WritePacket(time.Now().UTC(), b[:n]); err != nil && !errors.Is(err, layers.ErrTLSTooShort) {
257-
return err
258-
}
259-
}
279+
p := append([]byte(nil), b[:n]...)
280+
packetQueue <- p
260281
}
261282
}
262283
return nil

0 commit comments

Comments
 (0)