How To Read Network Packets

Share your advanced PureBasic knowledge/code with the community.
JustinJack
User
User
Posts: 89
Joined: Thu Feb 04, 2010 7:34 am
Location: Decatur, TX
Contact:

How To Read Network Packets

Post by JustinJack »

Hello. I figured I'd post something helpful. To use this, you need to install the open-source winPcap driver on your computer, it's a free library that includes a .dll
and a .lib file (at least). http://www.winpcap.org/install/default.htm. It also includes the source code (.c) for the drivers should you wish to tinker. But after
you install it this code is wonderful.

Code: Select all

;- Just a few help-y function I use here at top....

;- I prefer these mutex functions to the native, b/c the native mutex
;  function don't watch for mutexes that are still locked if a thread
;  has exited and the mutex is abandoned...

Procedure myReleaseMutex( mMutex )
    ProcedureReturn ReleaseMutex_(mMutex)
EndProcedure

Procedure myLockMutex( mMutex, myWait = #INFINITE )
    dwWaitResult = WaitForSingleObject_(mMutex, myWait)
    Select dwWaitResult
        Case #WAIT_OBJECT_0
            retVal = 1
        Case #WAIT_ABANDONED
            retVal = 1
        Case #WAIT_FAILED
            retVal = 0
        Case #WAIT_TIMEOUT
            retVal = 0
    EndSelect
    ProcedureReturn retVal
EndProcedure

Procedure.l myCreateMutex()
    ProcedureReturn CreateMutex_(#Null, #False, #Null)
EndProcedure


Procedure.s input32(title.s, request.s, defText.s = "", dwStyle = 0)
  mWndRect.RECT
  mWndSize.SIZE
  myWindow = OpenWindow(#PB_Any, 0, 0, 0, 0, title.s, #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_Invisible)
  hMyWnd = WindowID(myWindow)
  dwClassStyle = GetClassLongPtr_(hMyWnd, #GCL_STYLE) | #CS_SAVEBITS
  SetClassLongPtr_(hMyWnd, #GCL_STYLE, dwClassStyle)
  hWnd = WindowID(myWindow)
  hDc = GetDC_(hWnd)
  GetTextExtentPoint32_(hDc, @request, Len(request), @txtSize.SIZE)
  ReleaseDC_(hWnd, hDc)
  hDsk = GetDesktopWindow_()
  GetWindowRect_(hDsk, @dt.RECT)
  hTaskBar = FindWindow_("Shell_traywnd", "")
  GetWindowRect_(hTaskBar, @tb.RECT)
  tbHeight = tb\bottom-tb\top
  mWndSize\cx = txtSize\cx + 20
  mWndSize\cy = 160
  mWndRect\left = (((dt\right-dt\left) / 2) - (mWndSize\cx / 2))
  mWndRect\top  = (((dt\bottom-dt\top) - tbHeight) / 2) - 80
  SetWindowPos_(hWnd, #HWND_TOPMOST, mWndRect\left, mWndRect\top, mWndSize\cx, mWndSize\cy, #SWP_SHOWWINDOW)
  mText = TextGadget(#PB_Any, 0, 15, WindowWidth(myWindow)-5, 20, request, #PB_Text_Center)
  GetWindowRect_(GadgetID(mText), @text.RECT)
  padding = (GadgetWidth(mText) - txtSize\cx) 
  mInput = StringGadget(#PB_Any, padding, 40, GadgetWidth(mText) - (padding+5), 20, "", dwStyle)
  If defText <> ""
    SetGadgetText(mInput, defText)
    SendMessage_(GadgetID(mInput), #EM_SETSEL, 0, Len(defText))
  EndIf
  mOk = ButtonGadget(#PB_Any, (WindowWidth(myWindow)/2) - 50, 80, 100, 25, "OK")
  SetActiveGadget(mInput)
  BringWindowToTop_(hWnd)
  SetForegroundWindow_(hWnd)
  Repeat
    event = WaitWindowEvent()
    If event = #PB_Event_Gadget And EventGadget() = mOk And EventType() = #PB_EventType_LeftClick
      event = -1
    EndIf
    If event = #WM_KEYDOWN
      If EventwParam() = 13
        event = -1
      EndIf
    EndIf
  Until ((event = 16) Or (event = -1))
  If event <> 16
    retVal.s = GetGadgetText(mInput)
  EndIf
  CloseWindow(myWindow)
  ProcedureReturn retVal
EndProcedure

; - Begin code here
Structure ether_header
	ether_dhost.c[6] ;[ETHER_ADDR_LEN];
	ether_shost.c[6] ;[ETHER_ADDR_LEN];
	ether_type.w;
EndStructure


Structure ip
  ether_dhost.b[6];
	ether_shost.b[6];
	ether_type.w;
	ip_vhl.b;		/* header length, version */
	ip_tos.b;		/* type of service */
	ip_tle.w;		/* total length */
	ip_id.w;		/* identification */
	ip_off.w;		/* fragment offset field */
	ip_ttl.b;		/* time to live */
	ip_p.b;		  /* protocol */
	ip_sum.w;		/* checksum */
	ip_scr.c[4];
	ip_dst.c[4];
	udp_srcPort.w;
	udp_destPort.w;
	udp_length.w;
	udp_chksum.w;
EndStructure


Structure pcap_addr
  *next.pcap_addr
  *addr.SOCKADDR
  *netmask.SOCKADDR
  *broadaddr.SOCKADDR
  *dstaddr.SOCKADDR
EndStructure

Structure pcap_if_t
  *nextStruct
  *szDevName
  *szDescription
  *addressesptr
  flags.i
EndStructure

Structure pcap_pkthdr
  ts.TIMEVAL
  caplen.i
  len.i
EndStructure

Structure bpf_insn
  code.w
  jt.c
  jf.c
  k.i
EndStructure

Structure bpf_program
  bflen.i
  *bf_insns.bpf_insn
EndStructure

Structure myAdapters
  deviceName.s
  deviceDescription.s
  *addresses.pcap_addr
EndStructure

; _CDecl 
ImportC "C:\Users\Justin\Desktop\WpdPack_4_1_2\WpdPack\Lib\wpcap.lib"
  pcap_findalldevs.i(*lpPcap_if_t, *szerrbuf)
  pcap_open_live.l(*deviceName, snaplen.i, promisc.i, to_ms.i, *errorBuffer)
  pcap_compile.i(*pcap_t, *fp.bpf_program, *str, optimize.i, netmask.i)
  pcap_setfilter.i(*pcap_t, *fp.bpf_program)
  pcap_freecode(*fp.bpf_program)
  pcap_loop.i(*pcap_t, cnt.i, *lpFnCallBack, *lpUser)
  pcap_breakloop(*fp.bpf_program)
  pcap_close(*fp.bpf_program)
EndImport

Procedure getAllAdapters( List adpt.myAdapters() )
  errorBuffer.s = Space(256)
  *pcap_if_t_ptr.pcap_if_t
  If pcap_findalldevs(@*pcap_if_t_ptr, @errorBuffer) = -1
    MessageBox_(0, errorBuffer, "Error finding adapters...", #MB_OK|#MB_ICONERROR)
    ProcedureReturn 0
  EndIf
  ClearList(adpt())
  ResetList(adpt())
  Repeat 
    AddElement(adpt())
    adpt()\deviceName = PeekS(*pcap_if_t_ptr\szDevName)
    adpt()\deviceDescription = PeekS(*pcap_if_t_ptr\szDescription)
    adpt()\addresses = PeekL(*pcap_if_t_ptr\addressesptr)
    *pcap_if_t_ptr.pcap_if_t = *pcap_if_t_ptr\nextStruct
  Until *pcap_if_t_ptr = 0
  ProcedureReturn ListSize(adpt())
EndProcedure


; _CDecl
ProcedureC pktProcessProc( *useless, *pkthdr.pcap_pkthdr, *pktData )
  myTime = *pkthdr\ts\tv_sec
  *ipInfo.ip = *pktData
  totalLength = ntohs_(*ipInfo\ip_tle)
  ipVersion = (*ipInfo\ip_vhl >> 4)
  protocol = *ipInfo\ip_p
  ipFrom.s = StrU(*ipInfo\ip_dst[0]) + "."
  ipFrom.s + StrU(*ipInfo\ip_dst[1]) + "."
  ipFrom.s + StrU(*ipInfo\ip_dst[2]) + "."
  ipFrom.s + StrU(*ipInfo\ip_dst[3])
  ipTo.s = StrU(*ipInfo\ip_scr[0]) + "."
  ipTo.s + StrU(*ipInfo\ip_scr[1]) + "."
  ipTo.s + StrU(*ipInfo\ip_scr[2]) + "."
  ipTo.s + StrU(*ipInfo\ip_scr[3])
  myDataLength = ntohs_(*ipInfo\ip_tle)
  *peekAddr = *pktData + SizeOf(ether_header)
  If myDataLength > 1
    PrintN("Packet Received.")
    PrintN("----------------")
    Print("Protocol: ")
    Select protocol
      Case 1
        PrintN(" ICMP (Ping)")
      Case 6
        PrintN(" TCP")
      Case 12
        PrintN(" PUP")
      Case 17
        PrintN(" UDP")
      Default
        PrintN(" Other Protocol: " + Str(protocol))
    EndSelect
    PrintN("Source IP: " + ipFrom)
    PrintN("Destination IP: " + ipTo)
    PrintN("IPv" + Str(ipVersion))
    PrintN("----------------------------------------------")
    PrintN("")
  EndIf
EndProcedure

Structure startMonitorStructure
  adName.s
  stopMonSemaphore.l
  mainIpAddress.s
  *fp
EndStructure


Procedure monitorNetwork( *sms.startMonitorStructure )

 adapterName.s = *sms\adName
 myMonSemaphore = *sms\stopMonSemaphore
 mainIPAddress.s = *sms\mainIpAddress
 *fp = pcap_open_live(@adapterName, 65536, 1, 1000, @pcapOpenErrorBuffer.s)
 *sms\fp = *fp
 If (*fp)
  If Trim(mainIPAddress) <> ""
    myFilter.s = "ip host " + mainIPAddress
    filterProgram.bpf_program
    If pcap_compile(*fp, @filterProgram, @myFilter, 0, 0) <> -1
      If pcap_setfilter(*fp, @filterProgram) <> -1
        pcap_freecode(@filterProgram)
      Else
        MessageBox_(0, "pcap_setfilter() Failed.", "Error!", #MB_ICONERROR|#MB_OK)
      EndIf
    Else
      MessageBox_(0, "pcap_complie() Failed.", "Error!", #MB_ICONERROR|#MB_OK)
    EndIf
  EndIf
  iCode = pcap_loop(*fp, -1, @pktProcessProc(), #Null)
  Select iCode
    Case 0
      ;Debug "Successfully quit pcap_loop!"
    Case -1
      ;Debug "Error: " + pcapOpenErrorBuffer
    Case -2
      ;Debug "pcap_breakloop() called!"
    Default
      Debug "Not quite sure why we exited with a code of: " + Str(iCode)
   EndSelect
   SignalSemaphore(myMonSemaphore)
   pcap_close(*fp)
 Else
  SignalSemaphore(myMonSemaphore)
  MessageBox_(WindowID(myWindow), "AdapterName: " + adapterName.s, "pcap_open_live() Failed", #MB_ICONERROR|#MB_OK)
 EndIf
EndProcedure


Procedure main( mainIPAddress.s = "" )
  myWindow.l
  myDevSelect.l
  numAdapters = 0
  sms.startMonitorStructure
  OpenConsole()
  NewList NICAdapters.myAdapters()
  numAdapters = getAllAdapters(NICAdapters())
  If numAdapters > 0
    myWindow = OpenWindow(#PB_Any, 0, 0, 500, 500, "Packet Capture Window Selected IP: " + mainIPAddress, #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_SizeGadget)
    TextGadget(#PB_Any, 10, 10, 150, 20, "Select Device to Monitor:")
    myBeginButton = ButtonGadget(#PB_Any, 10, 40, 100, 25, "Begin Monitoring")
    myDevSelect = ComboBoxGadget(#PB_Any, 160, 8, 300, 20)
    ResetList(NICAdapters())
    While NextElement(NICAdapters())
      AddGadgetItem(myDevSelect, -1, NICAdapters()\deviceDescription)
    Wend
    SetGadgetState(myDevSelect, 0)
    Repeat
      myWindowEvent = WaitWindowEvent(500)
      If sms\stopMonSemaphore <> 0
        If TrySemaphore(sms\stopMonSemaphore)
          FreeSemaphore(sms\stopMonSemaphore)
          sms\stopMonSemaphore = 0
          DisableGadget(myBeginButton, 0)
        EndIf
      EndIf
      Select myWindowEvent
        Case #PB_Event_Gadget
          Select EventGadget()
              Case myBeginButton
                If EventType() = #PB_EventType_LeftClick
                  Select GetGadgetText(myBeginButton)
                    Case "Begin Monitoring"
                      pcapOpenErrorBuffer.s = Space(256)
                      mySelectedAdapter = GetGadgetState(myDevSelect)
                      SelectElement(NICAdapters(), mySelectedAdapter)
                      sms\adName = NICAdapters()\deviceName
                      sms\stopMonSemaphore = CreateSemaphore()
                      sms\mainIpAddress = mainIPAddress
                      monitoringActive = CreateThread(@monitorNetwork(), @sms)
                      SetGadgetText(myBeginButton, "Stop Monitoring")
                    Case "Stop Monitoring"
                      DisableGadget(myBeginButton, 1)
                      pcap_breakloop(sms\fp)
                      SetGadgetText(myBeginButton, "Begin Monitoring")
                  EndSelect
                EndIf
          EndSelect
      EndSelect
      
    Until myWindowEvent = 16
    CloseConsole()
  Else
    MessageBox_(0, "No WIRED Network adapters found!", "Error Message", #MB_ICONERROR|#MB_OK)
  EndIf
  If cProcessPhoneSystemSemaphore > 0
    SignalSemaphore(cProcessPhoneSystemSemaphore)
  EndIf
  ProcedureReturn 0
EndProcedure

main(input32("Specify IPv4 Address?", "Please enter IP Address Filter (optional)", ""))
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Re: How To Read Network Packets

Post by Joakim Christiansen »

Thanks, I always wanted some winPcap examples!
I like logic, hence I dislike humans but love computers.
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: How To Read Network Packets

Post by idle »

thanks
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
Michael Vogel
Addict
Addict
Posts: 2808
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: How To Read Network Packets

Post by Michael Vogel »

Fine, have to check that next week...
...maybe a sniffer (famous network analyzer which has been programmed in basic) should be possible to be done with PB now?

Michael
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: How To Read Network Packets

Post by Thorium »

Michael Vogel wrote: ...maybe a sniffer (famous network analyzer which has been programmed in basic) should be possible to be done with PB now?
It allways was possible, like most things. It's almost never the question if something is possible, the question is just how to make it possible.

I did a sniffer just with PB, without any 3rd party lib.
JustinJack
User
User
Posts: 89
Joined: Thu Feb 04, 2010 7:34 am
Location: Decatur, TX
Contact:

Re: How To Read Network Packets

Post by JustinJack »

Yes, that's exactly what I wrote it for. We have a SIP Server and VOIP phone system at work, and we wanted to have the incoming call info immediately when our CSR's answer the phone. Well, all the winPcap examples were in C, so I jumped on Visual Studio and wrote a program to use winPcap in c++ and read all the network packets, find the UDP ones (SIP uses UDP), parse and queue it in my analyze-y window and I could flip through them and figure out what it was talking about. Since NEC (the mfgr) is hard to get ahold of, and our installation company doesn't know sqaut, I had to. But all our other software is in PureBasic, and as we all know, dealing with strings is SOOOOO much less time consuming in PureBasic, I figured I'd figure out how to get it to work in PB, and it could very easily connect to our system's server application (also written in PB) and tell it what's going on with the phone system. But I stripped all that out for this version. You just pass winPcap the address of your _CDecl function which gets the entire packet, which in this example is:

"pktProcessProc( *useless, *pkthdr.pcap_pkthdr, *pktData )" and there you go. The actual data in the packet starts at *peekAddr

Using winPcap you can also send packets, which I was going to use to control our phones, since they're just dumb terminals displaying what the server tells them. It literally just tells them when to ring, shut-up, what lights to be on, what to display on the screen, and when to have the mike on and off.
User avatar
DoubleDutch
Addict
Addict
Posts: 3220
Joined: Thu Aug 07, 2003 7:01 pm
Location: United Kingdom
Contact:

Re: How To Read Network Packets

Post by DoubleDutch »

I did a sniffer just with PB, without any 3rd party lib
I'd like to look into doing this too. Do you have any source examples?
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: How To Read Network Packets

Post by Thorium »

DoubleDutch wrote:
I did a sniffer just with PB, without any 3rd party lib
I'd like to look into doing this too. Do you have any source examples?
Yes: http://www.purebasic.fr/english/viewtop ... =7&t=39881
Take a look at the NetHack plugin. It's basicly a winsock hook.
Unfortunatly all the comments are in german.

The point is: If you want to make a usermode sniffer you just hook the winsock API of the process you want to spy on.
User avatar
DoubleDutch
Addict
Addict
Posts: 3220
Joined: Thu Aug 07, 2003 7:01 pm
Location: United Kingdom
Contact:

Re: How To Read Network Packets

Post by DoubleDutch »

Thanks for the link. Hadn't seen that before, should be really useful. :)
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
F1337
New User
New User
Posts: 1
Joined: Sat May 28, 2011 10:02 am

Re: How To Read Network Packets

Post by F1337 »

Hi,
I really like your code but i miss an opportunity to read the packetcontent, because that's what i would need it for..
I already tried to read the packets with PCAP but i failed.

Can you help me?
wooly
New User
New User
Posts: 8
Joined: Mon Aug 04, 2008 7:54 pm

Re: How To Read Network Packets

Post by wooly »

Sorry for dragging up an old thread, but I was lead here by Google.

It seems this code would work for a project I have, problem is when I try to compile it I get a number of errors:

POLINK: error: Unresolved external symbol 'pcap_findalldevs'.
POLINK: error: Unresolved external symbol 'pcap_breakloop'.
POLINK: error: Unresolved external symbol 'pcap_open_live'.
POLINK: error: Unresolved external symbol 'pcap_compile'.
POLINK: error: Unresolved external symbol 'pcap_setfilter'.
POLINK: error: Unresolved external symbol 'pcap_freecode'.
POLINK: error: Unresolved external symbol 'pcap_pcap_loop'.
POLINK: error: Unresolved external symbol 'pcap_close'.
POLINK:fatal error:8 unresolved external(s)

Seems all the calls that rely on the library are not working. I have change line 152 to reflect the location of the library. I am using WpdPack 4.1.2 and PureBasic 4.60

Can anyone point me in the correct direction please

Wooly
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 796
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: How To Read Network Packets

Post by Zebuddi123 »

Translating the comments
http://www.purebasic.fr/english/viewtop ... 14&t=50324

Installed winpcap but cant find wpcap.lib ?

Zebuddi :D
malleo, caput, bang. Ego, comprehendunt in tempore
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: How To Read Network Packets

Post by jassing »

Zebuddi123 wrote:Translating the comments
http://www.purebasic.fr/english/viewtop ... 14&t=50324

Installed winpcap but cant find wpcap.lib ?

Zebuddi :D
you need the developer download. but the example above didn't run for me -- faled on an empty address for a peeks()
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 796
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: How To Read Network Packets

Post by Zebuddi123 »

Thanks jassing another homer simpson day for me Doh lol obvious lol


Zebuddi :D
malleo, caput, bang. Ego, comprehendunt in tempore
Post Reply