blob: 0a533380c6a270c7f56a55b2e87a34045ba75a25 [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// Copyright 2012 Google, Inc. All rights reserved.
2// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
3//
4// Use of this source code is governed by a BSD-style license
5// that can be found in the LICENSE file in the root of the source
6// tree.
7
8package pcap
9
10import (
11 "errors"
12 "fmt"
13 "os"
14 "runtime"
15 "sync"
16 "syscall"
17 "time"
18 "unsafe"
19
20 "github.com/google/gopacket"
21 "github.com/google/gopacket/layers"
22)
23
24var pcapLoaded = false
25
26const npcapPath = "\\Npcap"
27
28func initDllPath(kernel32 syscall.Handle) {
29 setDllDirectory, err := syscall.GetProcAddress(kernel32, "SetDllDirectoryA")
30 if err != nil {
31 // we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
32 return
33 }
34 getSystemDirectory, err := syscall.GetProcAddress(kernel32, "GetSystemDirectoryA")
35 if err != nil {
36 // we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
37 return
38 }
39 buf := make([]byte, 4096)
40 r, _, _ := syscall.Syscall(getSystemDirectory, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
41 if r == 0 || r > 4096-uintptr(len(npcapPath))-1 {
42 // we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
43 return
44 }
45 copy(buf[r:], npcapPath)
46 _, _, _ = syscall.Syscall(setDllDirectory, 1, uintptr(unsafe.Pointer(&buf[0])), 0, 0)
47 // ignore errors here - we just fallback to load wpcap.dll from default locations
48}
49
50// loadedDllPath will hold the full pathname of the loaded wpcap.dll after init if possible
51var loadedDllPath = "wpcap.dll"
52
53func initLoadedDllPath(kernel32 syscall.Handle) {
54 getModuleFileName, err := syscall.GetProcAddress(kernel32, "GetModuleFileNameA")
55 if err != nil {
56 // we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
57 return
58 }
59 buf := make([]byte, 4096)
60 r, _, _ := syscall.Syscall(getModuleFileName, 3, uintptr(wpcapHandle), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
61 if r == 0 {
62 // we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
63 return
64 }
65 loadedDllPath = string(buf[:int(r)])
66}
67
68func mustLoad(fun string) uintptr {
69 addr, err := syscall.GetProcAddress(wpcapHandle, fun)
70 if err != nil {
71 panic(fmt.Sprintf("Couldn't load function %s from %s", fun, loadedDllPath))
72 }
73 return addr
74}
75
76func mightLoad(fun string) uintptr {
77 addr, err := syscall.GetProcAddress(wpcapHandle, fun)
78 if err != nil {
79 return 0
80 }
81 return addr
82}
83
84func byteSliceToString(bval []byte) string {
85 for i := range bval {
86 if bval[i] == 0 {
87 return string(bval[:i])
88 }
89 }
90 return string(bval[:])
91}
92
93// bytePtrToString returns a string copied from pointer to a null terminated byte array
94// WARNING: ONLY SAFE WITH IF r POINTS TO C MEMORY!
95// govet will complain about this function for the reason stated above
96func bytePtrToString(r uintptr) string {
97 if r == 0 {
98 return ""
99 }
100 bval := (*[1 << 30]byte)(unsafe.Pointer(r))
101 return byteSliceToString(bval[:])
102}
103
104var wpcapHandle syscall.Handle
105var msvcrtHandle syscall.Handle
106var (
107 callocPtr,
108 pcapStrerrorPtr,
109 pcapStatustostrPtr,
110 pcapOpenLivePtr,
111 pcapOpenOfflinePtr,
112 pcapClosePtr,
113 pcapGeterrPtr,
114 pcapStatsPtr,
115 pcapCompilePtr,
116 pcapFreecodePtr,
117 pcapLookupnetPtr,
118 pcapOfflineFilterPtr,
119 pcapSetfilterPtr,
120 pcapListDatalinksPtr,
121 pcapFreeDatalinksPtr,
122 pcapDatalinkValToNamePtr,
123 pcapDatalinkValToDescriptionPtr,
124 pcapOpenDeadPtr,
125 pcapNextExPtr,
126 pcapDatalinkPtr,
127 pcapSetDatalinkPtr,
128 pcapDatalinkNameToValPtr,
129 pcapLibVersionPtr,
130 pcapFreealldevsPtr,
131 pcapFindalldevsPtr,
132 pcapSendpacketPtr,
133 pcapSetdirectionPtr,
134 pcapSnapshotPtr,
135 pcapTstampTypeValToNamePtr,
136 pcapTstampTypeNameToValPtr,
137 pcapListTstampTypesPtr,
138 pcapFreeTstampTypesPtr,
139 pcapSetTstampTypePtr,
140 pcapGetTstampPrecisionPtr,
141 pcapSetTstampPrecisionPtr,
142 pcapOpenOfflineWithTstampPrecisionPtr,
143 pcapHOpenOfflineWithTstampPrecisionPtr,
144 pcapActivatePtr,
145 pcapCreatePtr,
146 pcapSetSnaplenPtr,
147 pcapSetPromiscPtr,
148 pcapSetTimeoutPtr,
149 pcapCanSetRfmonPtr,
150 pcapSetRfmonPtr,
151 pcapSetBufferSizePtr,
152 pcapSetImmediateModePtr,
153 pcapHopenOfflinePtr uintptr
154)
155
156func init() {
157 LoadWinPCAP()
158}
159
160// LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions
161func LoadWinPCAP() error {
162 if pcapLoaded {
163 return nil
164 }
165
166 kernel32, err := syscall.LoadLibrary("kernel32.dll")
167 if err != nil {
168 return fmt.Errorf("couldn't load kernel32.dll")
169 }
170 defer syscall.FreeLibrary(kernel32)
171
172 initDllPath(kernel32)
173
174 wpcapHandle, err = syscall.LoadLibrary("wpcap.dll")
175 if err != nil {
176 return fmt.Errorf("couldn't load wpcap.dll")
177 }
178 initLoadedDllPath(kernel32)
179 msvcrtHandle, err = syscall.LoadLibrary("msvcrt.dll")
180 if err != nil {
181 return fmt.Errorf("couldn't load msvcrt.dll")
182 }
183 callocPtr, err = syscall.GetProcAddress(msvcrtHandle, "calloc")
184 if err != nil {
185 return fmt.Errorf("couldn't get calloc function")
186 }
187
188 pcapStrerrorPtr = mustLoad("pcap_strerror")
189 pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap
190 pcapOpenLivePtr = mustLoad("pcap_open_live")
191 pcapOpenOfflinePtr = mustLoad("pcap_open_offline")
192 pcapClosePtr = mustLoad("pcap_close")
193 pcapGeterrPtr = mustLoad("pcap_geterr")
194 pcapStatsPtr = mustLoad("pcap_stats")
195 pcapCompilePtr = mustLoad("pcap_compile")
196 pcapFreecodePtr = mustLoad("pcap_freecode")
197 pcapLookupnetPtr = mustLoad("pcap_lookupnet")
198 pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")
199 pcapSetfilterPtr = mustLoad("pcap_setfilter")
200 pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")
201 pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")
202 pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")
203 pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")
204 pcapOpenDeadPtr = mustLoad("pcap_open_dead")
205 pcapNextExPtr = mustLoad("pcap_next_ex")
206 pcapDatalinkPtr = mustLoad("pcap_datalink")
207 pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")
208 pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")
209 pcapLibVersionPtr = mustLoad("pcap_lib_version")
210 pcapFreealldevsPtr = mustLoad("pcap_freealldevs")
211 pcapFindalldevsPtr = mustLoad("pcap_findalldevs")
212 pcapSendpacketPtr = mustLoad("pcap_sendpacket")
213 pcapSetdirectionPtr = mustLoad("pcap_setdirection")
214 pcapSnapshotPtr = mustLoad("pcap_snapshot")
215 //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
216 pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")
217 pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")
218 pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")
219 pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")
220 pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")
221 pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")
222 pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")
223 pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")
224 pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")
225 pcapActivatePtr = mustLoad("pcap_activate")
226 pcapCreatePtr = mustLoad("pcap_create")
227 pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")
228 pcapSetPromiscPtr = mustLoad("pcap_set_promisc")
229 pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")
230 //winpcap does not support rfmon
231 pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")
232 pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")
233 pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")
234 //libpcap <1.5 does not have pcap_set_immediate_mode
235 pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")
236 pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")
237
238 pcapLoaded = true
239 return nil
240}
241
242func (h *pcapPkthdr) getSec() int64 {
243 return int64(h.Ts.Sec)
244}
245
246func (h *pcapPkthdr) getUsec() int64 {
247 return int64(h.Ts.Usec)
248}
249
250func (h *pcapPkthdr) getLen() int {
251 return int(h.Len)
252}
253
254func (h *pcapPkthdr) getCaplen() int {
255 return int(h.Caplen)
256}
257
258func statusError(status pcapCint) error {
259 var ret uintptr
260 if pcapStatustostrPtr == 0 {
261 ret, _, _ = syscall.Syscall(pcapStrerrorPtr, 1, uintptr(status), 0, 0)
262 } else {
263 ret, _, _ = syscall.Syscall(pcapStatustostrPtr, 1, uintptr(status), 0, 0)
264 }
265 return errors.New(bytePtrToString(ret))
266}
267
268func pcapGetTstampPrecision(cptr pcapTPtr) int {
269 if pcapGetTstampPrecisionPtr == 0 {
270 return pcapTstampPrecisionMicro
271 }
272 ret, _, _ := syscall.Syscall(pcapGetTstampPrecisionPtr, 1, uintptr(cptr), 0, 0)
273 return int(pcapCint(ret))
274}
275
276func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
277 if pcapSetTstampPrecisionPtr == 0 {
278 return errors.New("Not supported")
279 }
280 ret, _, _ := syscall.Syscall(pcapSetTstampPrecisionPtr, 2, uintptr(cptr), uintptr(precision), 0)
281 if pcapCint(ret) < 0 {
282 return errors.New("Not supported")
283 }
284 return nil
285}
286
287func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
288 err := LoadWinPCAP()
289 if err != nil {
290 return nil, err
291 }
292
293 buf := make([]byte, errorBufferSize)
294 dev, err := syscall.BytePtrFromString(device)
295 if err != nil {
296 return nil, err
297 }
298
299 cptr, _, _ := syscall.Syscall6(pcapOpenLivePtr, 5, uintptr(unsafe.Pointer(dev)), uintptr(snaplen), uintptr(pro), uintptr(timeout), uintptr(unsafe.Pointer(&buf[0])), 0)
300
301 if cptr == 0 {
302 return nil, errors.New(byteSliceToString(buf))
303 }
304 return &Handle{cptr: pcapTPtr(cptr)}, nil
305}
306
307func openOffline(file string) (handle *Handle, err error) {
308 err = LoadWinPCAP()
309 if err != nil {
310 return nil, err
311 }
312
313 buf := make([]byte, errorBufferSize)
314 f, err := syscall.BytePtrFromString(file)
315 if err != nil {
316 return nil, err
317 }
318
319 var cptr uintptr
320 if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
321 cptr, _, _ = syscall.Syscall(pcapOpenOfflinePtr, 2, uintptr(unsafe.Pointer(f)), uintptr(unsafe.Pointer(&buf[0])), 0)
322 } else {
323 cptr, _, _ = syscall.Syscall(pcapOpenOfflineWithTstampPrecisionPtr, 3, uintptr(unsafe.Pointer(f)), uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
324 }
325
326 if cptr == 0 {
327 return nil, errors.New(byteSliceToString(buf))
328 }
329
330 h := &Handle{cptr: pcapTPtr(cptr)}
331 return h, nil
332}
333
334func (p *Handle) pcapClose() {
335 if p.cptr != 0 {
336 _, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
337 }
338 p.cptr = 0
339}
340
341func (p *Handle) pcapGeterr() error {
342 ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
343 return errors.New(bytePtrToString(ret))
344}
345
346func (p *Handle) pcapStats() (*Stats, error) {
347 var cstats pcapStats
348 ret, _, _ := syscall.Syscall(pcapStatsPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&cstats)), 0)
349 if pcapCint(ret) < 0 {
350 return nil, p.pcapGeterr()
351 }
352 return &Stats{
353 PacketsReceived: int(cstats.Recv),
354 PacketsDropped: int(cstats.Drop),
355 PacketsIfDropped: int(cstats.Ifdrop),
356 }, nil
357}
358
359// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
360var pcapCompileMu sync.Mutex
361
362func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
363 var bpf pcapBpfProgram
364 cexpr, err := syscall.BytePtrFromString(expr)
365 if err != nil {
366 return pcapBpfProgram{}, err
367 }
368 pcapCompileMu.Lock()
369 defer pcapCompileMu.Unlock()
370 res, _, _ := syscall.Syscall6(pcapCompilePtr, 5, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), uintptr(unsafe.Pointer(cexpr)), uintptr(1), uintptr(maskp), 0)
371 if pcapCint(res) < 0 {
372 return bpf, p.pcapGeterr()
373 }
374 return bpf, nil
375}
376
377func (p pcapBpfProgram) free() {
378 _, _, _ = syscall.Syscall(pcapFreecodePtr, 1, uintptr(unsafe.Pointer(&p)), 0, 0)
379}
380
381func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
382 bpfInsn := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(p.Insns))[0:p.Len:p.Len]
383 bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
384
385 for i, v := range bpfInsn {
386 bpfInstruction[i].Code = v.Code
387 bpfInstruction[i].Jt = v.Jt
388 bpfInstruction[i].Jf = v.Jf
389 bpfInstruction[i].K = v.K
390 }
391 return bpfInstruction
392}
393
394func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
395 var bpf pcapBpfProgram
396 bpf.Len = uint32(len(bpfInstructions))
397 cbpfInsns, _, _ := syscall.Syscall(callocPtr, 2, uintptr(len(bpfInstructions)), uintptr(unsafe.Sizeof(bpfInstructions[0])), 0)
398 gbpfInsns := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
399
400 for i, v := range bpfInstructions {
401 gbpfInsns[i].Code = v.Code
402 gbpfInsns[i].Jt = v.Jt
403 gbpfInsns[i].Jf = v.Jf
404 gbpfInsns[i].K = v.K
405 }
406
407 bpf.Insns = (*pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
408 return bpf
409}
410
411func pcapLookupnet(device string) (netp, maskp uint32, err error) {
412 err = LoadWinPCAP()
413 if err != nil {
414 return 0, 0, err
415 }
416
417 buf := make([]byte, errorBufferSize)
418 dev, err := syscall.BytePtrFromString(device)
419 if err != nil {
420 return 0, 0, err
421 }
422 e, _, _ := syscall.Syscall6(pcapLookupnetPtr, 4, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&netp)), uintptr(unsafe.Pointer(&maskp)), uintptr(unsafe.Pointer(&buf[0])), 0, 0)
423 if pcapCint(e) < 0 {
424 return 0, 0, errors.New(byteSliceToString(buf))
425 }
426 return
427}
428
429func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
430 var hdr pcapPkthdr
431 hdr.Ts.Sec = int32(ci.Timestamp.Unix())
432 hdr.Ts.Usec = int32(ci.Timestamp.Nanosecond() / 1000)
433 hdr.Caplen = uint32(len(data)) // Trust actual length over ci.Length.
434 hdr.Len = uint32(ci.Length)
435 e, _, _ := syscall.Syscall(pcapOfflineFilterPtr, 3, uintptr(unsafe.Pointer(&b.bpf)), uintptr(unsafe.Pointer(&hdr)), uintptr(unsafe.Pointer(&data[0])))
436 return e != 0
437}
438
439func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
440 e, _, _ := syscall.Syscall(pcapSetfilterPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), 0)
441 if pcapCint(e) < 0 {
442 return p.pcapGeterr()
443 }
444 return nil
445}
446
447func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
448 var dltbuf *pcapCint
449 ret, _, _ := syscall.Syscall(pcapListDatalinksPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&dltbuf)), 0)
450
451 n := int(pcapCint(ret))
452
453 if n < 0 {
454 return nil, p.pcapGeterr()
455 }
456 defer syscall.Syscall(pcapFreeDatalinksPtr, 1, uintptr(unsafe.Pointer(dltbuf)), 0, 0)
457
458 datalinks = make([]Datalink, n)
459
460 dltArray := (*[1 << 28]pcapCint)(unsafe.Pointer(dltbuf))
461
462 for i := 0; i < n; i++ {
463 datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
464 datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
465 }
466
467 return datalinks, nil
468}
469
470func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
471 err := LoadWinPCAP()
472 if err != nil {
473 return nil, err
474 }
475
476 cptr, _, _ := syscall.Syscall(pcapOpenDeadPtr, 2, uintptr(linkType), uintptr(captureLength), 0)
477 if cptr == 0 {
478 return nil, errors.New("error opening dead capture")
479 }
480
481 return &Handle{cptr: pcapTPtr(cptr)}, nil
482}
483
484func (p *Handle) pcapNextPacketEx() NextError {
485 r, _, _ := syscall.Syscall(pcapNextExPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&p.pkthdr)), uintptr(unsafe.Pointer(&p.bufptr)))
486 ret := pcapCint(r)
487 // According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
488 // the return value of pcap_next_ex could be greater than 1 for success.
489 // Let's just make it 1 if it comes bigger than 1.
490 if ret > 1 {
491 ret = 1
492 }
493 return NextError(ret)
494}
495
496func (p *Handle) pcapDatalink() layers.LinkType {
497 ret, _, _ := syscall.Syscall(pcapDatalinkPtr, 1, uintptr(p.cptr), 0, 0)
498 return layers.LinkType(ret)
499}
500
501func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
502 ret, _, _ := syscall.Syscall(pcapSetDatalinkPtr, 2, uintptr(p.cptr), uintptr(dlt), 0)
503 if pcapCint(ret) < 0 {
504 return p.pcapGeterr()
505 }
506 return nil
507}
508
509func pcapDatalinkValToName(dlt int) string {
510 err := LoadWinPCAP()
511 if err != nil {
512 panic(err)
513 }
514 ret, _, _ := syscall.Syscall(pcapDatalinkValToNamePtr, 1, uintptr(dlt), 0, 0)
515 return bytePtrToString(ret)
516}
517
518func pcapDatalinkValToDescription(dlt int) string {
519 err := LoadWinPCAP()
520 if err != nil {
521 panic(err)
522 }
523 ret, _, _ := syscall.Syscall(pcapDatalinkValToDescriptionPtr, 1, uintptr(dlt), 0, 0)
524 return bytePtrToString(ret)
525}
526
527func pcapDatalinkNameToVal(name string) int {
528 err := LoadWinPCAP()
529 if err != nil {
530 panic(err)
531 }
532 cptr, err := syscall.BytePtrFromString(name)
533 if err != nil {
534 return 0
535 }
536 ret, _, _ := syscall.Syscall(pcapDatalinkNameToValPtr, 1, uintptr(unsafe.Pointer(cptr)), 0, 0)
537 return int(pcapCint(ret))
538}
539
540func pcapLibVersion() string {
541 err := LoadWinPCAP()
542 if err != nil {
543 panic(err)
544 }
545 ret, _, _ := syscall.Syscall(pcapLibVersionPtr, 0, 0, 0, 0)
546 return bytePtrToString(ret)
547}
548
549func (p *Handle) isOpen() bool {
550 return p.cptr != 0
551}
552
553type pcapDevices struct {
554 all, cur *pcapIf
555}
556
557func (p pcapDevices) free() {
558 syscall.Syscall(pcapFreealldevsPtr, 1, uintptr(unsafe.Pointer(p.all)), 0, 0)
559}
560
561func (p *pcapDevices) next() bool {
562 if p.cur == nil {
563 p.cur = p.all
564 if p.cur == nil {
565 return false
566 }
567 return true
568 }
569 if p.cur.Next == nil {
570 return false
571 }
572 p.cur = p.cur.Next
573 return true
574}
575
576func (p pcapDevices) name() string {
577 return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Name)))
578}
579
580func (p pcapDevices) description() string {
581 return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Description)))
582}
583
584func (p pcapDevices) flags() uint32 {
585 return p.cur.Flags
586}
587
588type pcapAddresses struct {
589 all, cur *pcapAddr
590}
591
592func (p *pcapAddresses) next() bool {
593 if p.cur == nil {
594 p.cur = p.all
595 if p.cur == nil {
596 return false
597 }
598 return true
599 }
600 if p.cur.Next == nil {
601 return false
602 }
603 p.cur = p.cur.Next
604 return true
605}
606
607func (p pcapAddresses) addr() *syscall.RawSockaddr {
608 return p.cur.Addr
609}
610
611func (p pcapAddresses) netmask() *syscall.RawSockaddr {
612 return p.cur.Netmask
613}
614
615func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
616 return p.cur.Broadaddr
617}
618
619func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
620 return p.cur.Dstaddr
621}
622
623func (p pcapDevices) addresses() pcapAddresses {
624 return pcapAddresses{all: p.cur.Addresses}
625}
626
627func pcapFindAllDevs() (pcapDevices, error) {
628 var alldevsp pcapDevices
629 err := LoadWinPCAP()
630 if err != nil {
631 return alldevsp, err
632 }
633
634 buf := make([]byte, errorBufferSize)
635
636 ret, _, _ := syscall.Syscall(pcapFindalldevsPtr, 2, uintptr(unsafe.Pointer(&alldevsp.all)), uintptr(unsafe.Pointer(&buf[0])), 0)
637
638 if pcapCint(ret) < 0 {
639 return pcapDevices{}, errors.New(byteSliceToString(buf))
640 }
641 return alldevsp, nil
642}
643
644func (p *Handle) pcapSendpacket(data []byte) error {
645 ret, _, _ := syscall.Syscall(pcapSendpacketPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&data[0])), uintptr(len(data)))
646 if pcapCint(ret) < 0 {
647 return p.pcapGeterr()
648 }
649 return nil
650}
651
652func (p *Handle) pcapSetdirection(direction Direction) error {
653 status, _, _ := syscall.Syscall(pcapSetdirectionPtr, 2, uintptr(p.cptr), uintptr(direction), 0)
654 if pcapCint(status) < 0 {
655 return statusError(pcapCint(status))
656 }
657 return nil
658}
659
660func (p *Handle) pcapSnapshot() int {
661 ret, _, _ := syscall.Syscall(pcapSnapshotPtr, 1, uintptr(p.cptr), 0, 0)
662 return int(pcapCint(ret))
663}
664
665func (t TimestampSource) pcapTstampTypeValToName() string {
666 err := LoadWinPCAP()
667 if err != nil {
668 return err.Error()
669 }
670
671 //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
672 if pcapTstampTypeValToNamePtr == 0 {
673 return "pcap timestamp types not supported"
674 }
675 ret, _, _ := syscall.Syscall(pcapTstampTypeValToNamePtr, 1, uintptr(t), 0, 0)
676 return bytePtrToString(ret)
677}
678
679func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
680 err := LoadWinPCAP()
681 if err != nil {
682 return 0, err
683 }
684
685 //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
686 if pcapTstampTypeNameToValPtr == 0 {
687 return 0, statusError(pcapCint(pcapError))
688 }
689 cs, err := syscall.BytePtrFromString(s)
690 if err != nil {
691 return 0, err
692 }
693 ret, _, _ := syscall.Syscall(pcapTstampTypeNameToValPtr, 1, uintptr(unsafe.Pointer(cs)), 0, 0)
694 t := pcapCint(ret)
695 if t < 0 {
696 return 0, statusError(pcapCint(t))
697 }
698 return TimestampSource(t), nil
699}
700
701func (p *InactiveHandle) pcapGeterr() error {
702 ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
703 return errors.New(bytePtrToString(ret))
704}
705
706func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
707 r, _, _ := syscall.Syscall(pcapActivatePtr, 1, uintptr(p.cptr), 0, 0)
708 ret := activateError(pcapCint(r))
709 if ret != aeNoError {
710 return nil, ret
711 }
712 h := &Handle{
713 cptr: p.cptr,
714 }
715 p.cptr = 0
716 return h, ret
717}
718
719func (p *InactiveHandle) pcapClose() {
720 if p.cptr != 0 {
721 _, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
722 }
723 p.cptr = 0
724}
725
726func pcapCreate(device string) (*InactiveHandle, error) {
727 err := LoadWinPCAP()
728 if err != nil {
729 return nil, err
730 }
731
732 buf := make([]byte, errorBufferSize)
733 dev, err := syscall.BytePtrFromString(device)
734 if err != nil {
735 return nil, err
736 }
737 cptr, _, _ := syscall.Syscall(pcapCreatePtr, 2, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&buf[0])), 0)
738 if cptr == 0 {
739 return nil, errors.New(byteSliceToString(buf))
740 }
741 return &InactiveHandle{cptr: pcapTPtr(cptr)}, nil
742}
743
744func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
745 status, _, _ := syscall.Syscall(pcapSetSnaplenPtr, 2, uintptr(p.cptr), uintptr(snaplen), 0)
746 if pcapCint(status) < 0 {
747 return statusError(pcapCint(status))
748 }
749 return nil
750}
751
752func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
753 var pro uintptr
754 if promisc {
755 pro = 1
756 }
757 status, _, _ := syscall.Syscall(pcapSetPromiscPtr, 2, uintptr(p.cptr), pro, 0)
758 if pcapCint(status) < 0 {
759 return statusError(pcapCint(status))
760 }
761 return nil
762}
763
764func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
765 status, _, _ := syscall.Syscall(pcapSetTimeoutPtr, 2, uintptr(p.cptr), uintptr(timeoutMillis(timeout)), 0)
766
767 if pcapCint(status) < 0 {
768 return statusError(pcapCint(status))
769 }
770 return nil
771}
772
773func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
774 //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
775 if pcapListTstampTypesPtr == 0 {
776 return
777 }
778 var types *pcapCint
779 ret, _, _ := syscall.Syscall(pcapListTstampTypesPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&types)), 0)
780 n := int(pcapCint(ret))
781 if n < 0 {
782 return // public interface doesn't have error :(
783 }
784 defer syscall.Syscall(pcapFreeTstampTypesPtr, 1, uintptr(unsafe.Pointer(types)), 0, 0)
785 typesArray := (*[1 << 28]pcapCint)(unsafe.Pointer(types))
786 for i := 0; i < n; i++ {
787 out = append(out, TimestampSource((*typesArray)[i]))
788 }
789 return
790}
791
792func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
793 //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
794 if pcapSetTstampTypePtr == 0 {
795 return statusError(pcapError)
796 }
797 status, _, _ := syscall.Syscall(pcapSetTstampTypePtr, 2, uintptr(p.cptr), uintptr(t), 0)
798 if pcapCint(status) < 0 {
799 return statusError(pcapCint(status))
800 }
801 return nil
802}
803
804func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
805 //winpcap does not support rfmon
806 if pcapCanSetRfmonPtr == 0 {
807 return CannotSetRFMon
808 }
809 var mon uintptr
810 if monitor {
811 mon = 1
812 }
813 canset, _, _ := syscall.Syscall(pcapCanSetRfmonPtr, 1, uintptr(p.cptr), 0, 0)
814 switch canset {
815 case 0:
816 return CannotSetRFMon
817 case 1:
818 // success
819 default:
820 return statusError(pcapCint(canset))
821 }
822 status, _, _ := syscall.Syscall(pcapSetRfmonPtr, 2, uintptr(p.cptr), mon, 0)
823 if status != 0 {
824 return statusError(pcapCint(status))
825 }
826 return nil
827}
828
829func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
830 status, _, _ := syscall.Syscall(pcapSetBufferSizePtr, 2, uintptr(p.cptr), uintptr(bufferSize), 0)
831 if pcapCint(status) < 0 {
832 return statusError(pcapCint(status))
833 }
834 return nil
835}
836
837func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
838 //libpcap <1.5 does not have pcap_set_immediate_mode
839 if pcapSetImmediateModePtr == 0 {
840 return statusError(pcapError)
841 }
842 var md uintptr
843 if mode {
844 md = 1
845 }
846 status, _, _ := syscall.Syscall(pcapSetImmediateModePtr, 2, uintptr(p.cptr), md, 0)
847 if pcapCint(status) < 0 {
848 return statusError(pcapCint(status))
849 }
850 return nil
851}
852
853func (p *Handle) setNonBlocking() error {
854 // do nothing
855 return nil
856}
857
858// waitForPacket waits for a packet or for the timeout to expire.
859func (p *Handle) waitForPacket() {
860 // can't use select() so instead just switch goroutines
861 runtime.Gosched()
862}
863
864// openOfflineFile returns contents of input file as a *Handle.
865func openOfflineFile(file *os.File) (handle *Handle, err error) {
866 err = LoadWinPCAP()
867 if err != nil {
868 return nil, err
869 }
870
871 buf := make([]byte, errorBufferSize)
872 cf := file.Fd()
873
874 var cptr uintptr
875 if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
876 cptr, _, _ = syscall.Syscall(pcapHopenOfflinePtr, 2, cf, uintptr(unsafe.Pointer(&buf[0])), 0)
877 } else {
878 cptr, _, _ = syscall.Syscall(pcapHOpenOfflineWithTstampPrecisionPtr, 3, cf, uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
879 }
880
881 if cptr == 0 {
882 return nil, errors.New(byteSliceToString(buf))
883 }
884 return &Handle{cptr: pcapTPtr(cptr)}, nil
885}