├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── codeql-analysis.yml │ └── python-package.yml ├── .gitignore ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── docs ├── _config.yml ├── admin_notes.md ├── api │ ├── api_auto.rst │ └── index.rst ├── authors.md ├── badges.md ├── changelog.md ├── contributing.md ├── creating_parsers.md ├── index.md ├── license.md ├── plans.md ├── print_http_requests.md ├── print_icmp.md └── print_packets.md ├── dpkt ├── __init__.py ├── ah.py ├── aim.py ├── aoe.py ├── aoeata.py ├── aoecfg.py ├── arp.py ├── asn1.py ├── bgp.py ├── cdp.py ├── compat.py ├── crc32c.py ├── dhcp.py ├── diameter.py ├── dns.py ├── dpkt.py ├── dtp.py ├── edp.py ├── esp.py ├── ethernet.py ├── gre.py ├── gzip.py ├── h225.py ├── hsrp.py ├── http.py ├── http2.py ├── icmp.py ├── icmp6.py ├── ieee80211.py ├── igmp.py ├── ip.py ├── ip6.py ├── ipip.py ├── ipx.py ├── llc.py ├── loopback.py ├── mrt.py ├── netbios.py ├── netflow.py ├── ntp.py ├── ospf.py ├── pcap.py ├── pcapng.py ├── pim.py ├── pmap.py ├── ppp.py ├── pppoe.py ├── qq.py ├── radiotap.py ├── radius.py ├── rfb.py ├── rip.py ├── rpc.py ├── rtcp.py ├── rtp.py ├── rx.py ├── sccp.py ├── sctp.py ├── sip.py ├── sll.py ├── sll2.py ├── smb.py ├── snoop.py ├── ssl.py ├── ssl_ciphersuites.py ├── stp.py ├── stun.py ├── tcp.py ├── telnet.py ├── tftp.py ├── tns.py ├── tpkt.py ├── udp.py ├── utils.py ├── vrrp.py └── yahoo.py ├── examples ├── __init__.py ├── data │ ├── README.md │ ├── dns_icmp.pcap │ ├── http.pcap │ ├── nb6-http.pcap │ ├── truncated_dns.pcap │ └── truncated_dns_2.pcap ├── old │ ├── dhcprequest.py │ ├── dnsping.py │ ├── nbtping.py │ └── ping.py ├── print_dns_truncated.py ├── print_http_requests.py ├── print_icmp.py └── print_packets.py ├── setup.cfg ├── setup.py └── tox.ini /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Details(please complete the following information):** 24 | - OS: [e.g. Windows10, Debian, etc] 25 | - Python Version [e.g. 3.8.6 ] 26 | - Please upload any pcap files that are needed to reproduce the issue. 27 | (Please try to have just the offending packets in the pcap to reduce upload size) 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '17 3 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'python' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-20.04 15 | strategy: 16 | matrix: 17 | python-version: ['2.7', '3.5', '3.6', '3.7', '3.8', '3.9', 'pypy3'] 18 | 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v2 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | python -m pip install flake8 pytest coverage pytest-cov 30 | 31 | - name: pytest and generate coverage report 32 | run: | 33 | coverage run --source dpkt -m pytest dpkt 34 | 35 | - name: Lint with flake8 36 | run: | 37 | # stop the build if there are Python syntax errors or undefined names 38 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 39 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 40 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 41 | 42 | - name: Coveralls Python 43 | uses: AndreMiras/coveralls-python-action@v20201129 44 | with: 45 | parallel: true 46 | flag-name: Unit Test - Python ${{ matrix.python-version }} 47 | github-token: ${{ secrets.GITHUB_TOKEN }} 48 | 49 | coveralls_finish: 50 | needs: build 51 | runs-on: ubuntu-latest 52 | steps: 53 | - name: Push to Coveralls 54 | uses: AndreMiras/coveralls-python-action@develop 55 | with: 56 | parallel-finished: true 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled/intermediate Python files 2 | *.py[cod] 3 | 4 | # C extensions 5 | *.so 6 | 7 | # Packages 8 | *.egg 9 | *.egg-info 10 | dist 11 | build 12 | sdist 13 | __pycache__ 14 | 15 | # Installer logs 16 | pip-log.txt 17 | 18 | # Unit test / coverage reports 19 | .coverage 20 | .tox 21 | .cache 22 | 23 | # iPython temp files 24 | .ipynb_checkpoints 25 | 26 | # Mac DS files 27 | .DS_Store 28 | 29 | # ReadTheDocs build directory 30 | _build 31 | 32 | # IntelliJ project files 33 | *.iml 34 | *.iws 35 | *.ipr 36 | .idea/ 37 | 38 | # eclipse project file 39 | .settings/ 40 | .classpath 41 | .project 42 | .pydevproject -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | Original author 3 | --------------- 4 | 5 | Dug Song 6 | 7 | 8 | Contributors 9 | ------------ 10 | 11 | Timur Alperovich 12 | radiotap module 13 | 14 | Nic Bellamy 15 | HTTP header parsing fix 16 | 17 | the grugq 18 | better RTP module 19 | 20 | David Helder 21 | bug fixes 22 | 23 | Przemyslaw Karwasiecki 24 | TABLE_DUMP in MRT module 25 | 26 | Reza Lotun 27 | MetaPacket cleanup 28 | 29 | Jeff Nathan 30 | bug fixes 31 | 32 | Tim Newsham 33 | IPv6 bugfixing and improvements 34 | 35 | keisuke.nishimoto@gmail.com 36 | Snoop file parser 37 | 38 | Jon Oberheide 39 | STUN, H.225, TPKT, NTP, RIP, Diameter, SCTP, BGP, MRT, RX modules 40 | 41 | plotnikoff@gmail.com 42 | handle dynamic imports from py2exe/freeze.py/zipped egg packages 43 | 44 | simdream@gmail.com 45 | handle multiple cookie values in HTTP 46 | 47 | Owen Stephens 48 | IP6 extension header support 49 | 50 | Robert Stone 51 | Netflow and QQ modules 52 | 53 | Thomas Taranowski 54 | dnet IP checksum bug on i386 55 | 56 | Jirka Vejrazka 57 | bug fixes 58 | 59 | Tim Yardley 60 | DHCP definitions 61 | 62 | Oscar Ibatullin 63 | pcapng module, core improvements, bit fields, pretty print, creating parsers doc 64 | 65 | Kyle Keppler 66 | Python 3 port 67 | 68 | Hao Sun 69 | Python 3 port 70 | 71 | Brian Wylie 72 | Examples, Docs, Tests, CI, Python 3 port 73 | 74 | crocogorical 75 | Extend test coverage 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2004 Dug Song 3 | All rights reserved, all wrongs reversed. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 3. The names of the authors and copyright holders may not be used to 15 | endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 19 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 20 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 | THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | 2 | include AUTHORS CHANGES README.rst LICENSE 3 | 4 | recursive-include docs * 5 | prune docs/_build 6 | 7 | global-exclude __pycache__/* 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | help: 3 | @echo "clean - remove all build/python artifacts" 4 | @echo "clean-build - remove build artifacts" 5 | @echo "clean-pyc - remove Python file artifacts" 6 | 7 | clean: clean-build clean-pyc 8 | 9 | clean-build: 10 | rm -fr build/ 11 | rm -fr dist/ 12 | rm -fr deb_dist/ 13 | rm -fr *.egg-info 14 | rm -fr *.tar.gz 15 | rm -fr .tox 16 | rm -fr .coverage 17 | rm -fr .cache 18 | rm -fr .pytest_cache 19 | find . -name '__pycache__' -exec rm -fr {} + 20 | 21 | clean-pyc: 22 | find . -name '*.pyc' -exec rm -f {} + 23 | find . -name '*.pyo' -exec rm -f {} + 24 | find . -name '*~' -exec rm -f {} + 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dpkt 2 | 3 | ![Python package](https://github.com/kbandla/dpkt/workflows/Python%20package/badge.svg) 4 | [![Coverage Status](https://coveralls.io/repos/github/kbandla/dpkt/badge.svg?branch=master)](https://coveralls.io/github/kbandla/dpkt?branch=master) 5 | [![supported-versions](https://img.shields.io/pypi/pyversions/dpkt.svg)](https://pypi.python.org/pypi/dpkt) 6 | [![supported-versions](https://img.shields.io/pypi/implementation/dpkt.svg)](https://pypi.python.org/pypi/dpkt) 7 | 8 | The dpkt project is a python module for fast, simple packet parsing, with definitions for the basic TCP/IP protocols. 9 | 10 | ### Installation 11 | ``` 12 | pip install dpkt 13 | ``` 14 | 15 | ### Examples and Documentation 16 | - [Main Docs for DPKT](https://kbandla.github.io/dpkt) 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker 2 | include: [ 'CONTRIBUTING.md', 'LICENSE.md' ] 3 | -------------------------------------------------------------------------------- /docs/admin_notes.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | ## PyPI Release How-To 4 | 5 | Notes and information on how to do the PyPI release for the dpkt 6 | project. For full details on packaging you can reference this page 7 | [Packaging](https://packaging.python.org/tutorials/packaging-projects/#packaging-your-project) 8 | 9 | The following instructions should work, but things change :) 10 | 11 | ### Package Requirements 12 | 13 | ``` bash 14 | - pip install tox 15 | - pip install --upgrade setuptools wheel 16 | - pip install twine 17 | ``` 18 | 19 | ### Setup pypirc 20 | 21 | The easiest thing to do is setup a \~/.pypirc file with the following 22 | contents 23 | 24 | ``` bash 25 | [distutils] 26 | index-servers = 27 | pypi 28 | testpypi 29 | 30 | [pypi] 31 | repository=https://upload.pypi.org/legacy/ 32 | username= 33 | password= 34 | 35 | [testpypi] 36 | repository=https://test.pypi.org/legacy/ 37 | username= 38 | password= 39 | ``` 40 | 41 | ### Tox Background 42 | 43 | Tox will install the dpkt package into a blank virtualenv and then 44 | execute all the tests against the newly installed package. So if 45 | everything goes okay, you know the pypi package installed fine and the 46 | tests (which pull from the installed dpkt package) also ran okay. 47 | 48 | ### Make sure ALL tests pass 49 | 50 | ``` bash 51 | $ cd dpkt 52 | $ tox 53 | ``` 54 | 55 | If ALL the test above pass... 56 | 57 | ### Create the TEST PyPI Release 58 | 59 | ``` bash 60 | $ vi dpkt/__init__.py and bump the version 61 | $ python setup.py sdist bdist_wheel 62 | $ twine upload dist/* -r testpypi 63 | ``` 64 | 65 | ### Install the TEST PyPI Release 66 | 67 | ``` bash 68 | $ pip install --index-url https://test.pypi.org/simple dpkt 69 | ``` 70 | 71 | ### Create the REAL PyPI Release 72 | 73 | ``` bash 74 | $ twine upload dist/* -r pypi 75 | ``` 76 | 77 | ### Push changes to Github 78 | 79 | ``` bash 80 | $ git add dpkt/__init__.py 81 | $ get commit -m "dpkt version 1.8.7 (or whatever)" 82 | $ git tag v1.8.7 (or whatever) 83 | $ git push --tags 84 | $ git push 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/api/index.rst: -------------------------------------------------------------------------------- 1 | 2 | API Reference 3 | ============= 4 | The dpkt API reference section is currently a work in progress, please have patience as we fill in and improve the documentation. 5 | 6 | **dpkt Modules** 7 | 8 | .. toctree:: 9 | :maxdepth: 4 10 | 11 | api_auto 12 | -------------------------------------------------------------------------------- /docs/authors.md: -------------------------------------------------------------------------------- 1 | # Authors 2 | 3 | ## Original author 4 | 5 | Dug Song \<\> 6 | 7 | ## Contributors 8 | 9 | - Timur Alperovich \<\> 10 | radiotap module 11 | 12 | - Nic Bellamy \<\> 13 | HTTP header parsing fix 14 | 15 | - the grugq \<\> 16 | better RTP module 17 | 18 | - David Helder \<\> 19 | bug fixes 20 | 21 | - Przemyslaw Karwasiecki \<\> 22 | TABLE\_DUMP in MRT module 23 | 24 | - Reza Lotun \<\> 25 | MetaPacket cleanup 26 | 27 | - Jeff Nathan \<\> 28 | bug fixes 29 | 30 | - Tim Newsham \<\> 31 | IPv6 bugfixing and improvements 32 | 33 | - 34 | Snoop file parser 35 | 36 | - Jon Oberheide \<\> 37 | STUN, H.225, TPKT, NTP, RIP, Diameter, SCTP, BGP, MRT, RX modules 38 | 39 | - 40 | handle dynamic imports from py2exe/freeze.py/zipped egg packages 41 | 42 | - 43 | handle multiple cookie values in HTTP 44 | 45 | - Owen Stephens \<\> 46 | IP6 extension header support 47 | 48 | - Robert Stone \<\> 49 | Netflow and QQ modules 50 | 51 | - Thomas Taranowski \<\> 52 | dnet IP checksum bug on i386 53 | 54 | - Jirka Vejrazka 55 | bug fixes 56 | 57 | - Tim Yardley \<\> 58 | DHCP definitions 59 | 60 | - Oscar Ibatullin \<\> 61 | pcapng module, core improvements, bit fields, pretty print, creating 62 | parsers doc 63 | 64 | - Kyle Keppler \<\> 65 | Python 3 port 66 | 67 | - Hao Sun \<\> 68 | Python 3 port 69 | 70 | - Brian Wylie \<\> 71 | Examples, Docs, Tests, CI, Python 3 port 72 | 73 | - crocogorical \<\> 74 | Extend test coverage 75 | 76 | - Schwaggot \<\> 77 | pcapng module, support for Packet Block and handling of UTF-8 option comments 78 | 79 | If you want to contribute to dpkt, see `contributing`. 80 | -------------------------------------------------------------------------------- /docs/badges.md: -------------------------------------------------------------------------------- 1 | [![Travis-CI Build 2 | Status](http://img.shields.io/travis/kbandla/dpkt.svg)](https://travis-ci.org/kbandla/dpkt) 3 | [![Coverage 4 | Status](http://img.shields.io/coveralls/kbandla/dpkt.svg)](https://coveralls.io/r/kbandla/dpkt) 5 | [![Code Quality 6 | Status](https://landscape.io/github/kbandla/dpkt/master/landscape.svg)](https://landscape.io/github/kbandla/dpkt/master) 7 | [![PyPI Package monthly 8 | downloads](http://img.shields.io/pypi/dm/dpkt.svg)](https://pypi.python.org/pypi/dpkt) 9 | [![PyPI Package latest 10 | release](http://img.shields.io/pypi/v/dpkt.svg)](https://pypi.python.org/pypi/dpkt) 11 | [![PyPI 12 | Wheel](https://img.shields.io/pypi/wheel/dpkt.svg)](https://pypi.python.org/pypi/dpkt) 13 | [![Supported 14 | versions](https://img.shields.io/pypi/pyversions/dpkt.svg)](https://pypi.python.org/pypi/dpkt) 15 | [![Supported 16 | implementations](https://img.shields.io/pypi/implementation/dpkt.svg)](https://pypi.python.org/pypi/dpkt) 17 | -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.9.8 4 | **[2022-08-17]** 5 | - Fixed endianness issues in PCAPNG, Loopback 6 | - Improved MPLS unpacking to include IPv6 7 | - Fixed unpacking of multiple records in TLS messages 8 | - Updated docstrings for multiples modules 9 | - Fixed a long-standing issue where serializing IP would change its length 10 | - Fixed IEEE 802.11 Beacon byte ordering 11 | - Graceful handling of PCAPNG option comment UTF-8 decoding errors 12 | - Added support for PCAPNG Packet Block 13 | - Added modpcap reader support 14 | 15 | ## 1.9.7.2 16 | **[2021-08-16]** 17 | - Fixed performance regression (https://github.com/kbandla/dpkt/issues/611) 18 | 19 | ## 1.9.7 20 | **[2021-08-16]** 21 | - Moved the project documentation from Read the Docs(RST) to github.io(MarkDown) 22 | - Added a new mechanism for creating bit-sized field definitions in the protocol parsers (Packet.\_\_bit_fields\_\_) 23 | - Added pretty printing capability aka Packet.pprint(), Packet.\_\_pprint_funcs\_\_ 24 | - Added documentation on developing protocol parsers in dpkt (creating_parsers.md) 25 | - Added a universal pcap+pcapng reader (dpkt.pcap.UniversalReader) 26 | - Improved TLS ClientHello and ServerHello parsing: return an "Unknown" ciphersuite instead of raising an exception, add codes for rfc8701, GREASE ciphersutes 27 | - Added function to get IP protocol name 28 | - Modified Packet.\_\_getitem\_\_() and added Packet.\_\_contains\_\_() to address the nested protocol layers 29 | - Fixed payload length interpretation in AH decoder 30 | - Improved handling of invalid chunks in HTTP and SCTP 31 | - Fixed decoding of IPv6 fragments after the 1st fragment 32 | - Support rfc3540 nonce sum flag in TCP 33 | 34 | ## 1.9.6 35 | **[2021-05-21]** 36 | - Added in the TLS 1.3 Cipher Suite from the RFC 8446 dated August 2018 37 | - Added support for Linux cooked capture v2, SLL2. 38 | 39 | ## 1.9.5 40 | **[2021-02-07]** 41 | 42 | - New example showing how to process truncated DNS packets (examples/print_dns_truncated.py). 43 | - Corrected typo in BGP.notification attribute. 44 | - BGP.Update.Attribute.MPReachNLRI.SNPA now inherits from dpkt.Packet. 45 | - Byteorder is now specified when packing GRE optional fields. 46 | - \#517: Improvement to Radiotap class, supporting multi-byte and misaligned flags fields. Endianness is now enforced. 47 | - Github issue template added for bug reporting. 48 | - Compliance with flake8 formatting. 49 | - asn1.py::utctime method now returns time in UTC, instead of local. 50 | - Allow multiple InterfaceDescriptionBlocks with pcapng.Writer. 51 | - SCTP decoder DATA chunk padding aligned to 4-bytes, and improved handling of .data field. 52 | - IEEE80211 DELBA frame now works on big and little-endian architectures. 53 | - Introduce compat.ntole which converts from network byte order to little-endian byte order, regardless of host endianness. 54 | - Ethernet class now attempts to unpack the padding and trailer if present. 55 | - Added anonymous property to cipher suites, which returns True if the cipher suite starts with 'anon'. 56 | - Added pfs (Perfect Forward Secrecy) and aead (Authenticated Encryption with Additional Data) properties to cipher suites. 57 | - Added old CHACHA20-POLY1305 related cipher suites to TLS CipherSuite list. 58 | - Remove redundant num_compression_methods from TLSClientHello 59 | - Testing improved from 90% coverage to over 99%. 60 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Report a Bug or Make a Feature Request 4 | 5 | Please go to the GitHub Issues page: 6 | . 7 | 8 | ## Checkout the Code 9 | 10 | ``` 11 | git clone https://github.com/kbandla/dpkt.git 12 | ``` 13 | 14 | ## Become a Developer 15 | 16 | The dpkt package uses the 'GitHub Flow' model: [GitHub 17 | Flow](http://scottchacon.com/2011/08/31/github-flow.html) 18 | 19 | If you'd like to submit a PR to fix/improve dpkt, you should create a 20 | 'fork' of the repository and open a Pull Request (PR) and one of the 21 | developers will review the PR and give feedback. The following page has good instructions on creating a PR from a fork: make a fork and then create a Pull Request . 22 | 23 | ### New Feature or Bug 24 | 25 | ``` 26 | $ git checkout -b my-awesome 27 | $ git push -u origin my-awesome 28 | $ ; git push 29 | $ ; git push 30 | $ pytest dpkt (this will run all the tests) 31 | ``` 32 | 33 | - Go to github and hit 'New pull request' 34 | - Someone reviews it and says 'AOK/give feedback and merges 35 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | # dpkt 3 | 4 | The dpkt project is a python module for fast, simple packet parsing, with definitions for the basic TCP/IP protocols. 5 | 6 | ### Installation 7 | ``` 8 | pip install dpkt 9 | ``` 10 | 11 | ### Examples 12 | - [Print Packets](print_packets.md) 13 | - [Print ICMP](print_icmp.md) 14 | - [Print HTTP](print_http_requests.md) 15 | 16 | ### Documentation 17 | - [DPKT Key Concepts for Creating Parsers](creating_parsers.md) 18 | - [Changelog](changelog.md) 19 | - [Authors](authors.md) 20 | - [Contributing](contributing.md) 21 | - [Project Plans (TBD)](plans.md) 22 | - [Admin Notes](admin_notes.md) 23 | 24 | ## About 25 | This code is based on [dpkt code](https://code.google.com/p/dpkt/) lead by Dug Song and is now being maintained and improved by an extended set of [developers](https://github.com/kbandla/dpkt/graphs/contributors). 26 | 27 | ## LICENSE 28 | 29 | BSD 3-Clause 30 | -------------------------------------------------------------------------------- /docs/license.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | BSD 3-Clause License, as the upstream project 4 | -------------------------------------------------------------------------------- /docs/plans.md: -------------------------------------------------------------------------------- 1 | # Development plans 2 | 3 | TBD: Insert Stuff Here 4 | -------------------------------------------------------------------------------- /docs/print_http_requests.md: -------------------------------------------------------------------------------- 1 | # Print HTTP Requests Example 2 | 3 | This example expands on the print\_packets example. It checks for HTTP 4 | request headers and displays their contents. 5 | 6 | **NOTE:** We are not reconstructing 'flows' so the request (and response 7 | if you tried to parse it) will only parse correctly if they fit within a 8 | single packet. Requests can often fit in a single packet but Responses 9 | almost never will. For proper reconstruction of flows you may want to 10 | look at other projects that use DPKT ( and 11 | others) 12 | 13 | **Code Excerpt** 14 | 15 | ``` python 16 | # For each packet in the pcap process the contents 17 | for timestamp, buf in pcap: 18 | 19 | # Unpack the Ethernet frame (mac src/dst, ethertype) 20 | eth = dpkt.ethernet.Ethernet(buf) 21 | 22 | # Make sure the Ethernet data contains an IP packet 23 | if not isinstance(eth.data, dpkt.ip.IP): 24 | print('Non IP Packet type not supported %s\n' % eth.data.__class__.__name__) 25 | continue 26 | 27 | # Now grab the data within the Ethernet frame (the IP packet) 28 | ip = eth.data 29 | 30 | # Check for TCP in the transport layer 31 | if isinstance(ip.data, dpkt.tcp.TCP): 32 | 33 | # Set the TCP data 34 | tcp = ip.data 35 | 36 | # Now see if we can parse the contents as a HTTP request 37 | try: 38 | request = dpkt.http.Request(tcp.data) 39 | except (dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError): 40 | continue 41 | 42 | # Pull out fragment information (flags and offset all packed into off field, so use bitmasks) 43 | do_not_fragment = bool(ip.off & dpkt.ip.IP_DF) 44 | more_fragments = bool(ip.off & dpkt.ip.IP_MF) 45 | fragment_offset = ip.off & dpkt.ip.IP_OFFMASK 46 | 47 | # Print out the info 48 | print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))) 49 | print('Ethernet Frame: ', mac_addr(eth.src), mac_addr(eth.dst), eth.type) 50 | print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)' % \ 51 | (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, more_fragments, fragment_offset)) 52 | print('HTTP request: %s\n' % repr(request)) 53 | ``` 54 | 55 | **Example Output** 56 | 57 | ``` 58 | Timestamp: 2004-05-13 10:17:08.222534 59 | Ethernet Frame: 00:00:01:00:00:00 fe:ff:20:00:01:00 2048 60 | IP: 145.254.160.237 -> 65.208.228.223 (len=519 ttl=128 DF=1 MF=0 offset=0) 61 | HTTP request: Request(body='', uri='/download.html', headers={'accept-language': 'en-us,en;q=0.5', 'accept-encoding': 'gzip,deflate', 'connection': 'keep-alive', 'keep-alive': '300', 'accept': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1', 'user-agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113', 'accept-charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'host': 'www.ethereal.com', 'referer': 'http://www.ethereal.com/development.html'}, version='1.1', data='', method='GET') 62 | 63 | Timestamp: 2004-05-13 10:17:10.295515 64 | Ethernet Frame: 00:00:01:00:00:00 fe:ff:20:00:01:00 2048 65 | IP: 145.254.160.237 -> 216.239.59.99 (len=761 ttl=128 DF=1 MF=0 offset=0) 66 | HTTP request: Request(body='', uri='/pagead/ads?client=ca-pub-2309191948673629&random=1084443430285&lmt=1082467020&format=468x60_as&output=html&url=http%3A%2F%2Fwww.ethereal.com%2Fdownload.html&color_bg=FFFFFF&color_text=333333&color_link=000000&color_url=666633&color_border=666633', headers={'accept-language': 'en-us,en;q=0.5', 'accept-encoding': 'gzip,deflate', 'connection': 'keep-alive', 'keep-alive': '300', 'accept': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1', 'user-agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113', 'accept-charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'host': 'pagead2.googlesyndication.com', 'referer': 'http://www.ethereal.com/download.html'}, version='1.1', data='', method='GET') 67 | 68 | ... 69 | ``` 70 | 71 | **See full code at: ** 72 | 73 | -------------------------------------------------------------------------------- /docs/print_icmp.md: -------------------------------------------------------------------------------- 1 | # Print ICMP Example 2 | 3 | This example expands on the print\_packets example. It checks for ICMP 4 | packets and displays the ICMP contents. 5 | 6 | **Code Excerpt** 7 | 8 | ``` python 9 | # For each packet in the pcap process the contents 10 | for timestamp, buf in pcap: 11 | 12 | # Unpack the Ethernet frame (mac src/dst, ethertype) 13 | eth = dpkt.ethernet.Ethernet(buf) 14 | 15 | # Make sure the Ethernet data contains an IP packet 16 | if not isinstance(eth.data, dpkt.ip.IP): 17 | print('Non IP Packet type not supported %s\n' % eth.data.__class__.__name__) 18 | continue 19 | 20 | # Now grab the data within the Ethernet frame (the IP packet) 21 | ip = eth.data 22 | 23 | # Now check if this is an ICMP packet 24 | if isinstance(ip.data, dpkt.icmp.ICMP): 25 | icmp = ip.data 26 | 27 | # Pull out fragment information (flags and offset all packed into off field, so use bitmasks) 28 | do_not_fragment = bool(ip.off & dpkt.ip.IP_DF) 29 | more_fragments = bool(ip.off & dpkt.ip.IP_MF) 30 | fragment_offset = ip.off & dpkt.ip.IP_OFFMASK 31 | 32 | # Print out the info 33 | print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))) 34 | print('Ethernet Frame: ', mac_addr(eth.src), mac_addr(eth.dst), eth.type) 35 | print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)' % \ 36 | (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, more_fragments, fragment_offset)) 37 | print('ICMP: type:%d code:%d checksum:%d data: %s\n' % (icmp.type, icmp.code, icmp.sum, repr(icmp.data))) 38 | ``` 39 | 40 | **Example Output** 41 | 42 | ``` 43 | Timestamp: 2013-05-30 22:45:17.283187 44 | Ethernet Frame: 60:33:4b:13:c5:58 02:1a:11:f0:c8:3b 2048 45 | IP: 192.168.43.9 -> 8.8.8.8 (len=84 ttl=64 DF=0 MF=0 offset=0) 46 | ICMP: type:8 code:0 checksum:48051 data: Echo(id=55099, data='Q\xa7\xd6}\x00\x04Q\xe4\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567') 47 | 48 | Timestamp: 2013-05-30 22:45:17.775391 49 | Ethernet Frame: 02:1a:11:f0:c8:3b 60:33:4b:13:c5:58 2048 50 | IP: 8.8.8.8 -> 192.168.43.9 (len=84 ttl=40 DF=0 MF=0 offset=0) 51 | ICMP: type:0 code:0 checksum:50099 data: Echo(id=55099, data='Q\xa7\xd6}\x00\x04Q\xe4\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567') 52 | 53 | ... 54 | ``` 55 | 56 | **Set full code at: ** 57 | 58 | -------------------------------------------------------------------------------- /docs/print_packets.md: -------------------------------------------------------------------------------- 1 | # Print Packets Example 2 | 3 | This example uses DPKT to read in a pcap file and print out the contents 4 | of the packets. This example is focused on the fields in the Ethernet 5 | Frame and IP packet. 6 | 7 | **Code Excerpt** 8 | 9 | ``` python 10 | # For each packet in the pcap process the contents 11 | for timestamp, buf in pcap: 12 | 13 | # Print out the timestamp in UTC 14 | print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))) 15 | 16 | # Unpack the Ethernet frame (mac src/dst, ethertype) 17 | eth = dpkt.ethernet.Ethernet(buf) 18 | print('Ethernet Frame: ', mac_addr(eth.src), mac_addr(eth.dst), eth.type) 19 | 20 | # Make sure the Ethernet frame contains an IP packet 21 | if not isinstance(eth.data, dpkt.ip.IP): 22 | print('Non IP Packet type not supported %s\n' % eth.data.__class__.__name__) 23 | continue 24 | 25 | # Now access the data within the Ethernet frame (the IP packet) 26 | # Pulling out src, dst, length, fragment info, TTL, and Protocol 27 | ip = eth.data 28 | 29 | # Print out the info, including the fragment flags and offset 30 | print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)\n' % 31 | (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, ip.df, ip.mf, ip.offset)) 32 | 33 | # Pretty print the last packet 34 | print('** Pretty print demo **\n') 35 | eth.pprint() 36 | ``` 37 | 38 | **Example Output** 39 | 40 | ``` 41 | Timestamp: 2004-05-13 10:17:07.311224 42 | Ethernet Frame: 00:00:01:00:00:00 fe:ff:20:00:01:00 2048 43 | IP: 145.254.160.237 -> 65.208.228.223 (len=48 ttl=128 DF=1 MF=0 offset=0) 44 | 45 | Timestamp: 2004-05-13 10:17:08.222534 46 | Ethernet Frame: fe:ff:20:00:01:00 00:00:01:00:00:00 2048 47 | IP: 65.208.228.223 -> 145.254.160.237 (len=48 ttl=47 DF=1 MF=0 offset=0) 48 | 49 | ** Pretty print demo ** 50 | 51 | Ethernet( 52 | dst=b'\x00\x00\x01\x00\x00\x00', # 00:00:01:00:00:00 53 | src=b'\xfe\xff \x00\x01\x00', # fe:ff:20:00:01:00 54 | type=2048, 55 | data=IP( 56 | v=4, 57 | hl=5, 58 | tos=0, 59 | len=40, 60 | id=0, 61 | off=16384, 62 | ttl=47, 63 | p=6, 64 | sum=62004, # 0xf234 65 | src=b'A\xd0\xe4\xdf', # 65.208.228.223 66 | dst=b'\x91\xfe\xa0\xed', # 145.254.160.237 67 | opts=b'', 68 | data=TCP( 69 | sport=80, 70 | dport=3372, 71 | seq=290236745, 72 | ack=951058420, 73 | off=5, 74 | flags=16, # ACK 75 | win=6432, 76 | sum=15459, # 0x3c63 77 | urp=0, 78 | opts=b'', 79 | ) # TCP 80 | ) # IP 81 | ) # Ethernet 82 | ``` 83 | 84 | **See full code at: ** 85 | 86 | -------------------------------------------------------------------------------- /dpkt/__init__.py: -------------------------------------------------------------------------------- 1 | """fast, simple packet creation and parsing.""" 2 | from __future__ import absolute_import 3 | from __future__ import division 4 | import sys 5 | 6 | __author__ = 'Various' 7 | __author_email__ = '' 8 | __license__ = 'BSD-3-Clause' 9 | __url__ = 'https://github.com/kbandla/dpkt' 10 | __version__ = '1.9.8' 11 | 12 | from .dpkt import * 13 | 14 | from . import ah 15 | from . import aoe 16 | from . import aim 17 | from . import arp 18 | from . import asn1 19 | from . import bgp 20 | from . import cdp 21 | from . import dhcp 22 | from . import diameter 23 | from . import dns 24 | from . import dtp 25 | from . import esp 26 | from . import ethernet 27 | from . import gre 28 | from . import gzip 29 | from . import h225 30 | from . import hsrp 31 | from . import http 32 | from . import http2 33 | from . import icmp 34 | from . import icmp6 35 | from . import ieee80211 36 | from . import igmp 37 | from . import ip 38 | from . import ip6 39 | from . import ipx 40 | from . import llc 41 | from . import loopback 42 | from . import mrt 43 | from . import netbios 44 | from . import netflow 45 | from . import ntp 46 | from . import ospf 47 | from . import pcap 48 | from . import pcapng 49 | from . import pim 50 | from . import pmap 51 | from . import ppp 52 | from . import pppoe 53 | from . import qq 54 | from . import radiotap 55 | from . import radius 56 | from . import rfb 57 | from . import rip 58 | from . import rpc 59 | from . import rtcp 60 | from . import rtp 61 | from . import rx 62 | from . import sccp 63 | from . import sctp 64 | from . import sip 65 | from . import sll 66 | from . import sll2 67 | from . import smb 68 | from . import ssl 69 | from . import stp 70 | from . import stun 71 | from . import tcp 72 | from . import telnet 73 | from . import tftp 74 | from . import tns 75 | from . import tpkt 76 | from . import udp 77 | from . import vrrp 78 | from . import yahoo 79 | 80 | # Note: list() is used to get a copy of the dict in order to avoid 81 | # "RuntimeError: dictionary changed size during iteration" 82 | # exception in Python 3 caused by _mod_init() funcs that load another modules 83 | for name, mod in list(sys.modules.items()): 84 | if name.startswith('dpkt.') and hasattr(mod, '_mod_init'): 85 | mod._mod_init() 86 | -------------------------------------------------------------------------------- /dpkt/ah.py: -------------------------------------------------------------------------------- 1 | # $Id: ah.py 34 2007-01-28 07:54:20Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | 4 | """Authentication Header.""" 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | from . import ip 9 | 10 | 11 | class AH(dpkt.Packet): 12 | """Authentication Header. 13 | 14 | The Authentication Header (AH) protocol provides data origin authentication, data integrity, and replay protection. 15 | 16 | Attributes: 17 | __hdr__: Header fields of AH. 18 | auth: Authentication body. 19 | data: Message data. 20 | """ 21 | 22 | __hdr__ = ( 23 | ('nxt', 'B', 0), 24 | ('len', 'B', 0), # payload length 25 | ('rsvd', 'H', 0), 26 | ('spi', 'I', 0), 27 | ('seq', 'I', 0) 28 | ) 29 | auth = b'' 30 | 31 | def unpack(self, buf): 32 | dpkt.Packet.unpack(self, buf) 33 | auth_len = max(4*self.len - 4, 0) # see RFC 4302, section 2.2 34 | self.auth = self.data[:auth_len] 35 | buf = self.data[auth_len:] 36 | 37 | try: 38 | self.data = ip.IP.get_proto(self.nxt)(buf) 39 | setattr(self, self.data.__class__.__name__.lower(), self.data) 40 | except (KeyError, dpkt.UnpackError): 41 | self.data = buf 42 | 43 | def __len__(self): 44 | return self.__hdr_len__ + len(self.auth) + len(self.data) 45 | 46 | def __bytes__(self): 47 | return self.pack_hdr() + bytes(self.auth) + bytes(self.data) 48 | 49 | 50 | def test_default_creation(): 51 | ah = AH() 52 | assert ah.nxt == 0 53 | assert ah.len == 0 54 | assert ah.rsvd == 0 55 | assert ah.spi == 0 56 | assert ah.seq == 0 57 | assert len(ah) == ah.__hdr_len__ 58 | assert bytes(ah) == b'\x00' * 12 59 | 60 | 61 | def test_creation_from_buf(): 62 | from binascii import unhexlify 63 | buf_ip = unhexlify( 64 | '04' # IP 65 | '0000000000000000000000' 66 | '4500002200000000401172c001020304' 67 | '01020304006f00de000ebf35666f6f626172' 68 | ) 69 | 70 | ah = AH(buf_ip) 71 | assert ah.nxt == 4 # IP 72 | assert isinstance(ah.data, ip.IP) 73 | assert len(ah) == 46 74 | assert bytes(ah) == buf_ip 75 | 76 | buf_not_ip = unhexlify( 77 | '37' # Not registered 78 | '0000000000000000000000' 79 | '4500002200000000401172c001020304' 80 | '01020304006f00de000ebf35666f6f626172' 81 | ) 82 | ah_not_ip = AH(buf_not_ip) 83 | assert ah_not_ip.nxt == 0x37 84 | assert isinstance(ah_not_ip.data, bytes) 85 | assert len(ah_not_ip) == 46 86 | assert bytes(ah_not_ip) == buf_not_ip 87 | -------------------------------------------------------------------------------- /dpkt/aim.py: -------------------------------------------------------------------------------- 1 | # $Id: aim.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | 4 | """AOL Instant Messenger.""" 5 | from __future__ import absolute_import 6 | 7 | import struct 8 | 9 | from . import dpkt 10 | 11 | # OSCAR: http://iserverd1.khstu.ru/oscar/ 12 | 13 | 14 | class FLAP(dpkt.Packet): 15 | """Frame Layer Protocol. 16 | 17 | See more about the FLAP on 18 | https://en.wikipedia.org/wiki/OSCAR_protocol#FLAP_header 19 | 20 | Attributes: 21 | __hdr__: Header fields of FLAP. 22 | data: Message data. 23 | """ 24 | 25 | __hdr__ = ( 26 | ('ast', 'B', 0x2a), # '*' 27 | ('type', 'B', 0), 28 | ('seq', 'H', 0), 29 | ('len', 'H', 0) 30 | ) 31 | 32 | def unpack(self, buf): 33 | dpkt.Packet.unpack(self, buf) 34 | if self.ast != 0x2a: 35 | raise dpkt.UnpackError('invalid FLAP header') 36 | if len(self.data) < self.len: 37 | raise dpkt.NeedData('%d left, %d needed' % (len(self.data), self.len)) 38 | 39 | 40 | class SNAC(dpkt.Packet): 41 | """Simple Network Atomic Communication. 42 | 43 | See more about the SNAC on 44 | https://en.wikipedia.org/wiki/OSCAR_protocol#SNAC_data 45 | 46 | Attributes: 47 | __hdr__: Header fields of SNAC. 48 | """ 49 | 50 | __hdr__ = ( 51 | ('family', 'H', 0), 52 | ('subtype', 'H', 0), 53 | ('flags', 'H', 0), 54 | ('reqid', 'I', 0) 55 | ) 56 | 57 | 58 | def tlv(buf): 59 | n = 4 60 | try: 61 | t, l_ = struct.unpack('>HH', buf[:n]) 62 | except struct.error: 63 | raise dpkt.UnpackError('invalid type, length fields') 64 | v = buf[n:n + l_] 65 | if len(v) < l_: 66 | raise dpkt.NeedData('%d left, %d needed' % (len(v), l_)) 67 | buf = buf[n + l_:] 68 | return t, l_, v, buf 69 | 70 | # TOC 1.0: http://jamwt.com/Py-TOC/PROTOCOL 71 | 72 | # TOC 2.0: http://www.firestuff.org/projects/firetalk/doc/toc2.txt 73 | 74 | 75 | def testAIM(): 76 | testdata = ( 77 | b'\x2a\x02\xac\xf3\x00\x81\x00\x03\x00\x0b\x00\x00\xfa\x45\x55\x64\x0e\x75\x73\x72\x6e\x61' 78 | b'\x6d\x65\x72\x65\x6d\x6f\x76\x65\x64\x00\x00\x00\x0a\x00\x01\x00\x02\x12\x90\x00\x44\x00' 79 | b'\x01\x00\x00\x03\x00\x04\x58\x90\x54\x36\x00\x45\x00\x04\x00\x00\x0f\x93\x00\x21\x00\x08' 80 | b'\x00\x85\x00\x7d\x00\x7d\x00\x00\x00\x41\x00\x01\x00\x00\x37\x00\x04\x00\x00\x00\x00\x00' 81 | b'\x0d\x00\x00\x00\x19\x00\x00\x00\x1d\x00\x24\x00\x00\x00\x05\x02\x01\xd2\x04\x72\x00\x01' 82 | b'\x00\x05\x02\x01\xd2\x04\x72\x00\x03\x00\x05\x2b\x00\x00\x2a\xcc\x00\x81\x00\x05\x2b\x00' 83 | b'\x00\x13\xf1' 84 | ) 85 | 86 | flap = FLAP(testdata) 87 | assert flap.ast == 0x2a 88 | assert flap.type == 0x02 89 | assert flap.seq == 44275 90 | assert flap.len == 129 91 | assert flap.data == ( 92 | b'\x00\x03\x00\x0b\x00\x00\xfa\x45\x55\x64\x0e\x75\x73\x72\x6e\x61\x6d\x65\x72\x65\x6d\x6f' 93 | b'\x76\x65\x64\x00\x00\x00\x0a\x00\x01\x00\x02\x12\x90\x00\x44\x00\x01\x00\x00\x03\x00\x04' 94 | b'\x58\x90\x54\x36\x00\x45\x00\x04\x00\x00\x0f\x93\x00\x21\x00\x08\x00\x85\x00\x7d\x00\x7d' 95 | b'\x00\x00\x00\x41\x00\x01\x00\x00\x37\x00\x04\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x19\x00' 96 | b'\x00\x00\x1d\x00\x24\x00\x00\x00\x05\x02\x01\xd2\x04\x72\x00\x01\x00\x05\x02\x01\xd2\x04' 97 | b'\x72\x00\x03\x00\x05\x2b\x00\x00\x2a\xcc\x00\x81\x00\x05\x2b\x00\x00\x13\xf1' 98 | ) 99 | 100 | snac = SNAC(flap.data) 101 | assert snac.family == 3 102 | assert snac.subtype == 11 103 | assert snac.flags == 0 104 | assert snac.reqid == 0xfa455564 105 | assert snac.data == ( 106 | b'\x0e\x75\x73\x72\x6e\x61\x6d\x65\x72\x65\x6d\x6f\x76\x65\x64\x00\x00\x00\x0a\x00\x01\x00' 107 | b'\x02\x12\x90\x00\x44\x00\x01\x00\x00\x03\x00\x04\x58\x90\x54\x36\x00\x45\x00\x04\x00\x00' 108 | b'\x0f\x93\x00\x21\x00\x08\x00\x85\x00\x7d\x00\x7d\x00\x00\x00\x41\x00\x01\x00\x00\x37\x00' 109 | b'\x04\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x19\x00\x00\x00\x1d\x00\x24\x00\x00\x00\x05\x02' 110 | b'\x01\xd2\x04\x72\x00\x01\x00\x05\x02\x01\xd2\x04\x72\x00\x03\x00\x05\x2b\x00\x00\x2a\xcc' 111 | b'\x00\x81\x00\x05\x2b\x00\x00\x13\xf1' 112 | ) 113 | 114 | # skip over the buddyname and TLV count in Oncoming Buddy message 115 | tlvdata = snac.data[19:] 116 | 117 | tlvCount = 0 118 | while tlvdata: 119 | t, l_, v, tlvdata = tlv(tlvdata) 120 | tlvCount += 1 121 | if tlvCount == 1: 122 | # just check function return for first TLV 123 | assert t == 0x01 124 | assert l_ == 2 125 | assert v == b'\x12\x90' 126 | assert tlvdata == ( 127 | b'\x00\x44\x00\x01\x00\x00\x03\x00\x04\x58\x90\x54\x36\x00\x45\x00\x04\x00\x00\x0f' 128 | b'\x93\x00\x21\x00\x08\x00\x85\x00\x7d\x00\x7d\x00\x00\x00\x41\x00\x01\x00\x00\x37' 129 | b'\x00\x04\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x19\x00\x00\x00\x1d\x00\x24\x00\x00' 130 | b'\x00\x05\x02\x01\xd2\x04\x72\x00\x01\x00\x05\x02\x01\xd2\x04\x72\x00\x03\x00\x05' 131 | b'\x2b\x00\x00\x2a\xcc\x00\x81\x00\x05\x2b\x00\x00\x13\xf1' 132 | ) 133 | 134 | # make sure we extracted 10 TLVs 135 | assert tlvCount == 10 136 | 137 | 138 | def testExceptions(): 139 | testdata = b'xxxxxx' 140 | try: 141 | FLAP(testdata) 142 | except dpkt.UnpackError as e: 143 | assert str(e) == 'invalid FLAP header' 144 | 145 | testdata = b'*\x02\x12\x34\x00\xff' 146 | try: 147 | FLAP(testdata) 148 | except dpkt.NeedData as e: 149 | assert str(e) == '0 left, 255 needed' 150 | 151 | try: 152 | t, l_, v, _ = tlv(b'x') 153 | except dpkt.UnpackError as e: 154 | assert str(e) == 'invalid type, length fields' 155 | 156 | try: 157 | t, l_, v, _ = tlv(b'\x00\x01\x00\xff') 158 | except dpkt.NeedData as e: 159 | assert str(e) == '0 left, 255 needed' 160 | -------------------------------------------------------------------------------- /dpkt/aoe.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ATA over Ethernet Protocol.""" 3 | from __future__ import absolute_import 4 | 5 | import struct 6 | 7 | from . import dpkt 8 | from .compat import iteritems 9 | 10 | 11 | class AOE(dpkt.Packet): 12 | """ATA over Ethernet Protocol. 13 | 14 | See more about the AOE on 15 | https://en.wikipedia.org/wiki/ATA_over_Ethernet 16 | 17 | Attributes: 18 | __hdr__: Header fields of AOE. 19 | data: Message data. 20 | """ 21 | 22 | __hdr__ = ( 23 | ('_ver_fl', 'B', 0x10), 24 | ('err', 'B', 0), 25 | ('maj', 'H', 0), 26 | ('min', 'B', 0), 27 | ('cmd', 'B', 0), 28 | ('tag', 'I', 0), 29 | ) 30 | __bit_fields__ = { 31 | '_ver_fl': ( 32 | ('ver', 4), 33 | ('fl', 4), 34 | ) 35 | } 36 | _cmdsw = {} 37 | 38 | @classmethod 39 | def set_cmd(cls, cmd, pktclass): 40 | cls._cmdsw[cmd] = pktclass 41 | 42 | @classmethod 43 | def get_cmd(cls, cmd): 44 | return cls._cmdsw[cmd] 45 | 46 | def unpack(self, buf): 47 | dpkt.Packet.unpack(self, buf) 48 | try: 49 | self.data = self._cmdsw[self.cmd](self.data) 50 | setattr(self, self.data.__class__.__name__.lower(), self.data) 51 | except (KeyError, struct.error, dpkt.UnpackError): 52 | pass 53 | 54 | 55 | AOE_CMD_ATA = 0 56 | AOE_CMD_CFG = 1 57 | AOE_FLAG_RSP = 1 << 3 58 | 59 | 60 | def _load_cmds(): 61 | prefix = 'AOE_CMD_' 62 | g = globals() 63 | 64 | for k, v in iteritems(g): 65 | if k.startswith(prefix): 66 | name = 'aoe' + k[len(prefix):].lower() 67 | try: 68 | mod = __import__(name, g, level=1) 69 | AOE.set_cmd(v, getattr(mod, name.upper())) 70 | except (ImportError, AttributeError): 71 | continue 72 | 73 | 74 | def _mod_init(): 75 | """Post-initialization called when all dpkt modules are fully loaded""" 76 | if not AOE._cmdsw: 77 | _load_cmds() 78 | 79 | 80 | def test_creation(): 81 | aoe = AOE() 82 | # hdr fields 83 | assert aoe._ver_fl == 0x10 84 | assert aoe.err == 0 85 | assert aoe.maj == 0 86 | assert aoe.min == 0 87 | assert aoe.cmd == 0 88 | assert aoe.tag == 0 89 | assert bytes(aoe) == b'\x10' + b'\x00' * 9 90 | 91 | 92 | def test_properties(): 93 | aoe = AOE() 94 | # property getters 95 | assert aoe.ver == 1 96 | assert aoe.fl == 0 97 | 98 | # property setters 99 | aoe.ver = 2 100 | assert aoe.ver == 2 101 | assert aoe._ver_fl == 0x20 102 | 103 | aoe.fl = 12 104 | assert aoe.fl == 12 105 | assert aoe._ver_fl == 0x2C 106 | 107 | 108 | def test_unpack(): 109 | from binascii import unhexlify 110 | buf = unhexlify( 111 | '1000000000' 112 | '00' # cmd: AOE_CMD_ATA 113 | '00000000' # tag 114 | ) 115 | aoe = AOE(buf) 116 | # AOE_CMD_ATA specified, but no data supplied 117 | assert aoe.data == b'' 118 | 119 | buf = unhexlify( 120 | '1000000000' 121 | '00' # cmd: AOE_CMD_ATA 122 | '00000000' # tag 123 | 124 | # AOEDATA specification 125 | '030a6b190000000045000028941f0000e30699b4232b2400de8e8442abd100500035e1' 126 | '2920d9000000229bf0e204656b' 127 | ) 128 | aoe = AOE(buf) 129 | assert aoe.aoeata == aoe.data 130 | 131 | 132 | def test_cmds(): 133 | import dpkt 134 | assert AOE.get_cmd(AOE_CMD_ATA) == dpkt.aoeata.AOEATA 135 | assert AOE.get_cmd(AOE_CMD_CFG) == dpkt.aoecfg.AOECFG 136 | 137 | 138 | def test_cmd_loading(): 139 | # this test checks that failing to load a module isn't catastrophic 140 | standard_cmds = AOE._cmdsw 141 | # delete the existing code->module mappings 142 | AOE._cmdsw = {} 143 | assert not AOE._cmdsw 144 | # create a new global constant pointing to a module which doesn't exist 145 | globals()['AOE_CMD_FAIL'] = "FAIL" 146 | _mod_init() 147 | # check that the same modules were loaded, ignoring the fail 148 | assert AOE._cmdsw == standard_cmds 149 | -------------------------------------------------------------------------------- /dpkt/aoeata.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ATA over Ethernet ATA command""" 3 | from __future__ import print_function 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | ATA_DEVICE_IDENTIFY = 0xec 9 | 10 | 11 | class AOEATA(dpkt.Packet): 12 | """ATA over Ethernet ATA command. 13 | 14 | See more about the AOEATA on 15 | https://en.wikipedia.org/wiki/ATA_over_Ethernet 16 | 17 | Attributes: 18 | __hdr__: Header fields of AOEATA. 19 | data: Message data. 20 | """ 21 | 22 | __hdr__ = ( 23 | ('aflags', 'B', 0), 24 | ('errfeat', 'B', 0), 25 | ('scnt', 'B', 0), 26 | ('cmdstat', 'B', ATA_DEVICE_IDENTIFY), 27 | ('lba0', 'B', 0), 28 | ('lba1', 'B', 0), 29 | ('lba2', 'B', 0), 30 | ('lba3', 'B', 0), 31 | ('lba4', 'B', 0), 32 | ('lba5', 'B', 0), 33 | ('res', 'H', 0), 34 | ) 35 | 36 | # XXX: in unpack, switch on ATA command like icmp does on type 37 | 38 | 39 | def test_aoeata(): 40 | s = (b'\x03\x0a\x6b\x19\x00\x00\x00\x00\x45\x00\x00\x28\x94\x1f\x00\x00\xe3\x06\x99\xb4\x23\x2b' 41 | b'\x24\x00\xde\x8e\x84\x42\xab\xd1\x00\x50\x00\x35\xe1\x29\x20\xd9\x00\x00\x00\x22\x9b\xf0\xe2\x04\x65\x6b') 42 | aoeata = AOEATA(s) 43 | assert (bytes(aoeata) == s) 44 | -------------------------------------------------------------------------------- /dpkt/aoecfg.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ATA over Ethernet ATA command""" 3 | from __future__ import print_function 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | 9 | class AOECFG(dpkt.Packet): 10 | """ATA over Ethernet ATA command. 11 | 12 | See more about the AOE on \ 13 | https://en.wikipedia.org/wiki/ATA_over_Ethernet 14 | 15 | Attributes: 16 | __hdr__: Header fields of AOECFG. 17 | data: Message data. 18 | """ 19 | 20 | __hdr__ = ( 21 | ('bufcnt', 'H', 0), 22 | ('fwver', 'H', 0), 23 | ('scnt', 'B', 0), 24 | ('aoeccmd', 'B', 0), 25 | ('cslen', 'H', 0), 26 | ) 27 | 28 | 29 | def test_aoecfg(): 30 | s = (b'\x01\x02\x03\x04\x05\x06\x11\x12\x13\x14\x15\x16\x88\xa2\x10\x00\x00\x01\x02\x01\x80' 31 | b'\x00\x00\x00\x12\x34\x00\x00\x00\x00\x04\x00' + b'\0xed' * 1024) 32 | aoecfg = AOECFG(s[14 + 10:]) 33 | assert (aoecfg.bufcnt == 0x1234) 34 | -------------------------------------------------------------------------------- /dpkt/arp.py: -------------------------------------------------------------------------------- 1 | # $Id: arp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Address Resolution Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | # Hardware address format 9 | ARP_HRD_ETH = 0x0001 # ethernet hardware 10 | ARP_HRD_IEEE802 = 0x0006 # IEEE 802 hardware 11 | 12 | # Protocol address format 13 | ARP_PRO_IP = 0x0800 # IP protocol 14 | 15 | # ARP operation 16 | ARP_OP_REQUEST = 1 # request to resolve ha given pa 17 | ARP_OP_REPLY = 2 # response giving hardware address 18 | ARP_OP_REVREQUEST = 3 # request to resolve pa given ha 19 | ARP_OP_REVREPLY = 4 # response giving protocol address 20 | 21 | 22 | class ARP(dpkt.Packet): 23 | """Address Resolution Protocol. 24 | 25 | See more about the ARP on \ 26 | https://en.wikipedia.org/wiki/Address_Resolution_Protocol 27 | 28 | Attributes: 29 | __hdr__: Header fields of ARP. 30 | """ 31 | 32 | __hdr__ = ( 33 | ('hrd', 'H', ARP_HRD_ETH), 34 | ('pro', 'H', ARP_PRO_IP), 35 | ('hln', 'B', 6), # hardware address length 36 | ('pln', 'B', 4), # protocol address length 37 | ('op', 'H', ARP_OP_REQUEST), 38 | ('sha', '6s', b''), 39 | ('spa', '4s', b''), 40 | ('tha', '6s', b''), 41 | ('tpa', '4s', b'') 42 | ) 43 | -------------------------------------------------------------------------------- /dpkt/cdp.py: -------------------------------------------------------------------------------- 1 | # $Id: cdp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Cisco Discovery Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | CDP_DEVID = 1 # string 9 | CDP_ADDRESS = 2 10 | CDP_PORTID = 3 # string 11 | CDP_CAPABILITIES = 4 # 32-bit bitmask 12 | CDP_VERSION = 5 # string 13 | CDP_PLATFORM = 6 # string 14 | CDP_IPPREFIX = 7 15 | 16 | CDP_VTP_MGMT_DOMAIN = 9 # string 17 | CDP_NATIVE_VLAN = 10 # 16-bit integer 18 | CDP_DUPLEX = 11 # 8-bit boolean 19 | CDP_TRUST_BITMAP = 18 # 8-bit bitmask0x13 20 | CDP_UNTRUST_COS = 19 # 8-bit port 21 | CDP_SYSTEM_NAME = 20 # string 22 | CDP_SYSTEM_OID = 21 # 10-byte binary string 23 | CDP_MGMT_ADDRESS = 22 # 32-bit number of addrs, Addresses 24 | CDP_LOCATION = 23 # string 25 | 26 | 27 | class CDP(dpkt.Packet): 28 | """Cisco Discovery Protocol. 29 | 30 | Cisco Discovery Protocol (CDP) is a proprietary Data Link Layer protocol developed by Cisco Systems in 1994 31 | by Keith McCloghrie and Dino Farinacci. It is used to share information about other directly connected 32 | Cisco equipment, such as the operating system version and IP address. 33 | 34 | See more on 35 | https://en.wikipedia.org/wiki/Cisco_Discovery_Protocol 36 | 37 | Attributes: 38 | __hdr__: Header fields of CDP. 39 | version: (int): CDP protocol version. (1 byte) 40 | ttl: (int): Time to live. The amount of time in seconds that a receiver should retain the information 41 | contained in this packet. (1 byte) 42 | sum: (int): Checksum. (2 bytes) 43 | """ 44 | 45 | __hdr__ = ( 46 | ('version', 'B', 2), 47 | ('ttl', 'B', 180), 48 | ('sum', 'H', 0) 49 | ) 50 | 51 | class TLV(dpkt.Packet): 52 | """Type–length–value 53 | 54 | When constructing the packet, len is not mandatory: 55 | if not provided, then self.data must be this exact TLV payload 56 | 57 | Attributes: 58 | __hdr__: Header fields of TLV. 59 | type: (int): Type (2 bytes) 60 | len: (int): The total length in bytes of the Type, Length and Data fields. (2 bytes) 61 | """ 62 | 63 | __hdr__ = ( 64 | ('type', 'H', 0), 65 | ('len', 'H', 0) 66 | ) 67 | 68 | def data_len(self): 69 | if self.len: 70 | return self.len - self.__hdr_len__ 71 | return len(self.data) 72 | 73 | def unpack(self, buf): 74 | dpkt.Packet.unpack(self, buf) 75 | self.data = self.data[:self.data_len()] 76 | 77 | def __len__(self): 78 | return self.__hdr_len__ + len(self.data) 79 | 80 | def __bytes__(self): 81 | if hasattr(self, 'len') and not self.len: 82 | self.len = len(self) 83 | return self.pack_hdr() + bytes(self.data) 84 | 85 | class Address(TLV): 86 | # XXX - only handle NLPID/IP for now 87 | __hdr__ = ( 88 | ('ptype', 'B', 1), # protocol type (NLPID) 89 | ('plen', 'B', 1), # protocol length 90 | ('p', 'B', 0xcc), # IP 91 | ('alen', 'H', 4) # address length 92 | ) 93 | 94 | def data_len(self): 95 | return self.alen 96 | 97 | class TLV_Addresses(TLV): 98 | __hdr__ = ( 99 | ('type', 'H', CDP_ADDRESS), 100 | ('len', 'H', 0), # 17), 101 | ('Addresses', 'L', 1), 102 | ) 103 | 104 | def unpack(self, buf): 105 | dpkt.Packet.unpack(self, buf) 106 | buf = self.data 107 | l_ = [] 108 | while buf: 109 | # find the right TLV according to Type value 110 | tlv_find_type = self.TLV(buf).type 111 | # if this TLV is not in tlv_types, use the default TLV class 112 | tlv = self.tlv_types.get(tlv_find_type, self.TLV)(buf) 113 | l_.append(bytes(tlv)) 114 | buf = buf[len(tlv):] 115 | self.tlvs = l_ 116 | self.data = b''.join(l_) 117 | 118 | def __len__(self): 119 | return self.__hdr_len__ + len(self.data) 120 | 121 | def __bytes__(self): 122 | data = bytes(self.data) 123 | if not self.sum: 124 | self.sum = dpkt.in_cksum(self.pack_hdr() + data) 125 | return self.pack_hdr() + data 126 | 127 | # keep here the TLV classes whose header is different from the generic TLV header (example : TLV_Addresses) 128 | tlv_types = {CDP_ADDRESS: TLV_Addresses} 129 | 130 | 131 | def test_cdp(): 132 | import socket 133 | from . import ethernet 134 | 135 | ss = (b'\x02\xb4\xdf\x93\x00\x01\x00\x09\x63\x69\x73\x63\x6f\x00\x02\x00\x11\x00\x00\x00\x01' 136 | b'\x01\x01\xcc\x00\x04\xc0\xa8\x01\x67') 137 | rr1 = CDP(ss) 138 | assert bytes(rr1) == ss 139 | 140 | # construction 141 | ss = (b'\x02\xb4\xdf\x93\x00\x01\x00\x09\x63\x69\x73\x63\x6f\x00\x02\x00\x11\x00\x00\x00\x01' 142 | b'\x01\x01\xcc\x00\x04\xc0\xa8\x01\x67') 143 | p1 = CDP.TLV_Addresses(data=CDP.Address(data=socket.inet_aton('192.168.1.103'))) 144 | p2 = CDP.TLV(type=CDP_DEVID, data=b'cisco') 145 | data = p2.pack() + p1.pack() 146 | rr2 = CDP(data=data) 147 | assert bytes(rr2) == ss 148 | 149 | s = (b'\x01\x00\x0c\xcc\xcc\xcc\xc4\x022k\x00\x00\x01T\xaa\xaa\x03\x00\x00\x0c \x00\x02\xb4,B' 150 | b'\x00\x01\x00\x06R2\x00\x05\x00\xffCisco IOS Software, 3700 Software (C3745-ADVENTERPRI' 151 | b'SEK9_SNA-M), Version 12.4(25d), RELEASE SOFTWARE (fc1)\nTechnical Support: http://www.' 152 | b'cisco.com/techsupport\nCopyright (c) 1986-2010 by Cisco Systems, Inc.\nCompiled Wed 18' 153 | b'-Aug-10 08:18 by prod_rel_team\x00\x06\x00\x0eCisco 3745\x00\x02\x00\x11\x00\x00\x00\x01' 154 | b'\x01\x01\xcc\x00\x04\n\x00\x00\x02\x00\x03\x00\x13FastEthernet0/0\x00\x04\x00\x08\x00' 155 | b'\x00\x00)\x00\t\x00\x04\x00\x0b\x00\x05\x00') 156 | eth = ethernet.Ethernet(s) 157 | assert isinstance(eth.data.data, CDP) 158 | assert len(eth.data.data.tlvs) == 8 # number of CDP TLVs; ensures they are decoded 159 | assert str(eth) == str(s) 160 | assert len(eth) == len(s) 161 | 162 | 163 | def test_tlv(): 164 | from binascii import unhexlify 165 | # len field set to 0 166 | buf_no_len = unhexlify( 167 | '0000' # type 168 | '0000' # len 169 | 'abcd' # data 170 | ) 171 | 172 | buf_with_len = unhexlify( 173 | '0000' # type 174 | '0006' # len 175 | 'abcd' # data 176 | ) 177 | tlv = CDP.TLV(buf_no_len) 178 | assert tlv.type == 0 179 | assert tlv.len == 0 180 | assert tlv.data_len() == 2 181 | assert tlv.data == b'\xab\xcd' 182 | assert bytes(tlv) == buf_with_len 183 | 184 | # len field set manually 185 | tlv = CDP.TLV(buf_with_len) 186 | assert tlv.type == 0 187 | assert tlv.len == 6 188 | assert tlv.data_len() == 2 189 | assert tlv.data == b'\xab\xcd' 190 | assert bytes(tlv) == buf_with_len 191 | 192 | 193 | def test_address(): 194 | from binascii import unhexlify 195 | buf = unhexlify( 196 | '00' # ptype 197 | '11' # plen 198 | '22' # p 199 | '3333' # alen 200 | ) 201 | address = CDP.Address(buf) 202 | assert address.data_len() == 0x3333 203 | -------------------------------------------------------------------------------- /dpkt/compat.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from struct import pack, unpack 4 | import sys 5 | 6 | if sys.version_info < (3,): 7 | compat_ord = ord 8 | else: 9 | def compat_ord(char): 10 | return char 11 | 12 | try: 13 | from itertools import izip 14 | compat_izip = izip 15 | except ImportError: 16 | compat_izip = zip 17 | 18 | try: 19 | from cStringIO import StringIO 20 | except ImportError: 21 | from io import StringIO 22 | 23 | try: 24 | from BytesIO import BytesIO 25 | except ImportError: 26 | from io import BytesIO 27 | 28 | if sys.version_info < (3,): 29 | def iteritems(d, **kw): 30 | return d.iteritems(**kw) 31 | 32 | def intround(num): 33 | return int(round(num)) 34 | 35 | else: 36 | def iteritems(d, **kw): 37 | return iter(d.items(**kw)) 38 | 39 | # python3 will return an int if you round to 0 decimal places 40 | intround = round 41 | 42 | 43 | def ntole(v): 44 | """convert a 2-byte word from the network byte order (big endian) to little endian; 45 | replaces socket.ntohs() to work on both little and big endian architectures 46 | """ 47 | return unpack('> 8) ^ crc32c_table[(crc ^ b) & 0xff] 70 | return crc 71 | 72 | 73 | def done(crc): 74 | tmp = ~crc & 0xffffffff 75 | b0 = tmp & 0xff 76 | b1 = (tmp >> 8) & 0xff 77 | b2 = (tmp >> 16) & 0xff 78 | b3 = (tmp >> 24) & 0xff 79 | crc = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3 80 | return crc 81 | 82 | 83 | def cksum(buf): 84 | """Return computed CRC-32c checksum.""" 85 | return done(add(0xffffffff, buf)) 86 | 87 | 88 | def test_crc32c(): 89 | 90 | def bswap32(x): 91 | from struct import pack, unpack 92 | return unpack('I', x))[0] 93 | 94 | # reference test value from CRC catalogue 95 | # http://reveng.sourceforge.net/crc-catalogue/17plus.htm#crc.cat.crc-32c 96 | # SCTP uses tranport-level mirrored byte ordering, so we bswap32 97 | 98 | assert cksum(b'') == 0 99 | assert cksum(b'123456789') == bswap32(0xe3069283) 100 | -------------------------------------------------------------------------------- /dpkt/dtp.py: -------------------------------------------------------------------------------- 1 | # $Id: dtp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Dynamic Trunking Protocol.""" 4 | from __future__ import absolute_import 5 | import struct 6 | 7 | from . import dpkt 8 | 9 | TRUNK_NAME = 0x01 10 | MAC_ADDR = 0x04 11 | 12 | 13 | class DTP(dpkt.Packet): 14 | """Dynamic Trunking Protocol. 15 | 16 | The Dynamic Trunking Protocol (DTP) is a proprietary networking protocol developed by Cisco Systems for the purpose 17 | of negotiating trunking on a link between two VLAN-aware switches, and for negotiating the type of trunking 18 | encapsulation to be used. It works on Layer 2 of the OSI model. VLAN trunks formed using DTP may utilize either 19 | IEEE 802.1Q or Cisco ISL trunking protocols. 20 | 21 | Attributes: 22 | __hdr__: Header fields of DTP. 23 | v: (int) Version. (1 byte) 24 | """ 25 | 26 | __hdr__ = ( 27 | ('v', 'B', 0), 28 | ) # rest is TLVs 29 | 30 | def unpack(self, buf): 31 | dpkt.Packet.unpack(self, buf) 32 | buf = self.data 33 | tvs = [] 34 | while buf: 35 | t, l_ = struct.unpack('>HH', buf[:4]) 36 | v, buf = buf[4:4 + l_], buf[4 + l_:] 37 | tvs.append((t, v)) 38 | self.data = tvs 39 | 40 | def __bytes__(self): 41 | return b''.join([struct.pack('>HH', t, len(v)) + v for t, v in self.data]) 42 | 43 | 44 | def test_creation(): 45 | dtp1 = DTP() 46 | assert dtp1.v == 0 47 | 48 | from binascii import unhexlify 49 | buf = unhexlify( 50 | '04' 51 | '0001' # type 52 | '0002' # length 53 | '1234' # value 54 | ) 55 | 56 | dtp2 = DTP(buf) 57 | assert dtp2.v == 4 58 | assert len(dtp2.data) == 1 59 | tlvs = dtp2.data 60 | tlv = tlvs[0] 61 | key, value = tlv 62 | assert key == 1 63 | assert value == unhexlify('1234') 64 | 65 | assert bytes(dtp2) == buf[1:] 66 | -------------------------------------------------------------------------------- /dpkt/edp.py: -------------------------------------------------------------------------------- 1 | """Extreme Discovery Protocol.""" 2 | from __future__ import absolute_import 3 | 4 | import dpkt 5 | 6 | 7 | class EDP(dpkt.Packet): 8 | __hdr__ = ( 9 | ('version', 'B', 1), 10 | ('reserved', 'B', 0), 11 | ('hlen', 'H', 0), 12 | ('sum', 'H', 0), 13 | ('seq', 'H', 0), 14 | ('mid', 'H', 0), 15 | ('mac', '6s', b'') 16 | ) 17 | 18 | def __bytes__(self): 19 | if not self.sum: 20 | self.sum = dpkt.in_cksum(dpkt.Packet.__bytes__(self)) 21 | return dpkt.Packet.__bytes__(self) 22 | 23 | 24 | class TestEDP(object): 25 | """ 26 | Test basic EDP functionality. 27 | """ 28 | 29 | @classmethod 30 | def setup_class(cls): 31 | from binascii import unhexlify 32 | cls.buf = unhexlify( 33 | '01' # version 34 | '00' # reserved 35 | '013c' # hlen 36 | '9e76' # sum 37 | '001b' # seq 38 | '0000' # mid 39 | '080027' # mac 40 | '2d90ed990200240000000000000000000000000f020207000000000000000000000000000000009901010445584f532d32000000000000000' 41 | '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' 42 | '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' 43 | '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' 44 | '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' 45 | '00000000000000000000000000000000099000004' 46 | ) 47 | cls.p = EDP(cls.buf) 48 | 49 | def test_version(self): 50 | assert (self.p.version == 1) 51 | 52 | def test_reserved(self): 53 | assert (self.p.reserved == 0) 54 | 55 | def test_hlen(self): 56 | assert (self.p.hlen == 316) 57 | 58 | def test_sum(self): 59 | assert (self.p.sum == 40566) 60 | 61 | def test_seq(self): 62 | assert (self.p.seq == 27) 63 | 64 | def test_mid(self): 65 | assert (self.p.mid == 0) 66 | 67 | def test_mac(self): 68 | assert (self.p.mac == b"\x08\x00'-\x90\xed") 69 | 70 | def test_bytes(self): 71 | assert bytes(self.p) == self.buf 72 | 73 | # force recalculation of the checksum 74 | edp = EDP(self.buf) 75 | edp.sum = 0 76 | assert edp.sum == 0 77 | assert bytes(edp) == self.buf 78 | -------------------------------------------------------------------------------- /dpkt/esp.py: -------------------------------------------------------------------------------- 1 | # $Id: esp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Encapsulated Security Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | 9 | class ESP(dpkt.Packet): 10 | """Encapsulated Security Protocol. 11 | 12 | Encapsulating Security Payload (ESP) is a member of the Internet Protocol Security (IPsec) set of protocols that 13 | encrypt and authenticate the packets of data between computers using a Virtual Private Network (VPN). The focus 14 | and layer on which ESP operates makes it possible for VPNs to function securely. 15 | 16 | Attributes: 17 | __hdr__: Header fields of ESP. 18 | spi: (int): Security Parameters Index. An arbitrary value that, in combination with the destination 19 | IP address and security protocol (ESP), uniquely identifies the SA for this datagram. (4 bytes) 20 | spi: (int): Sequence number. This field contains a monotonically increasing counter value. (4 bytes) 21 | """ 22 | 23 | __hdr__ = ( 24 | ('spi', 'I', 0), 25 | ('seq', 'I', 0) 26 | ) 27 | -------------------------------------------------------------------------------- /dpkt/hsrp.py: -------------------------------------------------------------------------------- 1 | # $Id: hsrp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Cisco Hot Standby Router Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | # Opcodes 9 | HELLO = 0 10 | COUP = 1 11 | RESIGN = 2 12 | 13 | # States 14 | INITIAL = 0x00 15 | LEARN = 0x01 16 | LISTEN = 0x02 17 | SPEAK = 0x04 18 | STANDBY = 0x08 19 | ACTIVE = 0x10 20 | 21 | 22 | class HSRP(dpkt.Packet): 23 | """Cisco Hot Standby Router Protocol. 24 | 25 | It is a Cisco proprietary redundancy protocol for establishing a fault-tolerant default gateway. Version 1 of the 26 | protocol was described in RFC 2281 in 1998. Version 2 of the protocol includes improvements and supports IPv6 but 27 | there is no corresponding RFC published for this version. 28 | 29 | Attributes: 30 | __hdr__: Header fields of HSRP. 31 | version: (int): Version. HSRP version number. (1 byte) 32 | opcode: (int): Operation code. (Hello - 0, Coup - 1, Resign - 2) (1 byte) 33 | state: (int): State. This field describes the current state of the router sending the message. (1 byte) 34 | hello: (int): Hellotime. This field is only meaningful in Hello messages. It contains the approximate period 35 | between the Hello messages that the router sends. The time is given in seconds.(1 byte) 36 | hold: (int): Holdtime. This field is only meaningful in Hello messages. It contains the amount of time that 37 | the current Hello message should be considered valid. The time is given in seconds. (1 byte) 38 | priority: (int): Priority. This field is used to elect the active and standby routers. (1 byte) 39 | group: (int): Group. This field identifies the standby group. (1 byte) 40 | rsvd: (int): Reserved. (1 byte) 41 | auth: (bytes): Authentication Data. This field contains a clear text 8 character reused password. (8 bytes) 42 | vip: (bytes): Virtual IP Address. The virtual IP address used by this group. (4 bytes) 43 | """ 44 | 45 | __hdr__ = ( 46 | ('version', 'B', 0), 47 | ('opcode', 'B', 0), 48 | ('state', 'B', 0), 49 | ('hello', 'B', 0), 50 | ('hold', 'B', 0), 51 | ('priority', 'B', 0), 52 | ('group', 'B', 0), 53 | ('rsvd', 'B', 0), 54 | ('auth', '8s', b'cisco'), 55 | ('vip', '4s', b'') 56 | ) 57 | -------------------------------------------------------------------------------- /dpkt/icmp.py: -------------------------------------------------------------------------------- 1 | # $Id: icmp.py 45 2007-08-03 00:05:22Z jon.oberheide $ 2 | # -*- coding: utf-8 -*- 3 | """Internet Control Message Protocol.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | 9 | # Types (icmp_type) and codes (icmp_code) - 10 | # http://www.iana.org/assignments/icmp-parameters 11 | 12 | ICMP_CODE_NONE = 0 # for types without codes 13 | ICMP_ECHOREPLY = 0 # echo reply 14 | ICMP_UNREACH = 3 # dest unreachable, codes: 15 | ICMP_UNREACH_NET = 0 # bad net 16 | ICMP_UNREACH_HOST = 1 # bad host 17 | ICMP_UNREACH_PROTO = 2 # bad protocol 18 | ICMP_UNREACH_PORT = 3 # bad port 19 | ICMP_UNREACH_NEEDFRAG = 4 # IP_DF caused drop 20 | ICMP_UNREACH_SRCFAIL = 5 # src route failed 21 | ICMP_UNREACH_NET_UNKNOWN = 6 # unknown net 22 | ICMP_UNREACH_HOST_UNKNOWN = 7 # unknown host 23 | ICMP_UNREACH_ISOLATED = 8 # src host isolated 24 | ICMP_UNREACH_NET_PROHIB = 9 # for crypto devs 25 | ICMP_UNREACH_HOST_PROHIB = 10 # ditto 26 | ICMP_UNREACH_TOSNET = 11 # bad tos for net 27 | ICMP_UNREACH_TOSHOST = 12 # bad tos for host 28 | ICMP_UNREACH_FILTER_PROHIB = 13 # prohibited access 29 | ICMP_UNREACH_HOST_PRECEDENCE = 14 # precedence error 30 | ICMP_UNREACH_PRECEDENCE_CUTOFF = 15 # precedence cutoff 31 | ICMP_SRCQUENCH = 4 # packet lost, slow down 32 | ICMP_REDIRECT = 5 # shorter route, codes: 33 | ICMP_REDIRECT_NET = 0 # for network 34 | ICMP_REDIRECT_HOST = 1 # for host 35 | ICMP_REDIRECT_TOSNET = 2 # for tos and net 36 | ICMP_REDIRECT_TOSHOST = 3 # for tos and host 37 | ICMP_ALTHOSTADDR = 6 # alternate host address 38 | ICMP_ECHO = 8 # echo service 39 | ICMP_RTRADVERT = 9 # router advertise, codes: 40 | ICMP_RTRADVERT_NORMAL = 0 # normal 41 | ICMP_RTRADVERT_NOROUTE_COMMON = 16 # selective routing 42 | ICMP_RTRSOLICIT = 10 # router solicitation 43 | ICMP_TIMEXCEED = 11 # time exceeded, code: 44 | ICMP_TIMEXCEED_INTRANS = 0 # ttl==0 in transit 45 | ICMP_TIMEXCEED_REASS = 1 # ttl==0 in reass 46 | ICMP_PARAMPROB = 12 # ip header bad 47 | ICMP_PARAMPROB_ERRATPTR = 0 # req. opt. absent 48 | ICMP_PARAMPROB_OPTABSENT = 1 # req. opt. absent 49 | ICMP_PARAMPROB_LENGTH = 2 # bad length 50 | ICMP_TSTAMP = 13 # timestamp request 51 | ICMP_TSTAMPREPLY = 14 # timestamp reply 52 | ICMP_INFO = 15 # information request 53 | ICMP_INFOREPLY = 16 # information reply 54 | ICMP_MASK = 17 # address mask request 55 | ICMP_MASKREPLY = 18 # address mask reply 56 | ICMP_TRACEROUTE = 30 # traceroute 57 | ICMP_DATACONVERR = 31 # data conversion error 58 | ICMP_MOBILE_REDIRECT = 32 # mobile host redirect 59 | ICMP_IP6_WHEREAREYOU = 33 # IPv6 where-are-you 60 | ICMP_IP6_IAMHERE = 34 # IPv6 i-am-here 61 | ICMP_MOBILE_REG = 35 # mobile registration req 62 | ICMP_MOBILE_REGREPLY = 36 # mobile registration reply 63 | ICMP_DNS = 37 # domain name request 64 | ICMP_DNSREPLY = 38 # domain name reply 65 | ICMP_SKIP = 39 # SKIP 66 | ICMP_PHOTURIS = 40 # Photuris 67 | ICMP_PHOTURIS_UNKNOWN_INDEX = 0 # unknown sec index 68 | ICMP_PHOTURIS_AUTH_FAILED = 1 # auth failed 69 | ICMP_PHOTURIS_DECOMPRESS_FAILED = 2 # decompress failed 70 | ICMP_PHOTURIS_DECRYPT_FAILED = 3 # decrypt failed 71 | ICMP_PHOTURIS_NEED_AUTHN = 4 # no authentication 72 | ICMP_PHOTURIS_NEED_AUTHZ = 5 # no authorization 73 | ICMP_TYPE_MAX = 40 74 | 75 | 76 | class ICMP(dpkt.Packet): 77 | """Internet Control Message Protocol. 78 | 79 | The Internet Control Message Protocol (ICMP) is a supporting protocol in the Internet protocol suite. 80 | It is used by network devices, including routers, to send error messages and operational information 81 | indicating success or failure when communicating with another IP address. 82 | 83 | Attributes: 84 | __hdr__: Header fields of ICMP. 85 | type: (int): ICMP type (1 byte) 86 | code: (int): ICMP subtype (1 byte) 87 | sum: (int): Internet checksum (RFC 1071) for error checking, 88 | calculated from the ICMP header and data with value 0 substituted for this field. (2 bytes) 89 | """ 90 | 91 | __hdr__ = ( 92 | ('type', 'B', 8), 93 | ('code', 'B', 0), 94 | ('sum', 'H', 0) 95 | ) 96 | 97 | class Echo(dpkt.Packet): 98 | __hdr__ = (('id', 'H', 0), ('seq', 'H', 0)) 99 | 100 | class Quote(dpkt.Packet): 101 | __hdr__ = (('pad', 'I', 0),) 102 | 103 | def unpack(self, buf): 104 | dpkt.Packet.unpack(self, buf) 105 | from . import ip 106 | self.data = self.ip = ip.IP(self.data) 107 | 108 | class Unreach(Quote): 109 | __hdr__ = (('pad', 'H', 0), ('mtu', 'H', 0)) 110 | 111 | class Quench(Quote): 112 | pass 113 | 114 | class Redirect(Quote): 115 | __hdr__ = (('gw', 'I', 0),) 116 | 117 | class ParamProbe(Quote): 118 | __hdr__ = (('ptr', 'B', 0), ('pad1', 'B', 0), ('pad2', 'H', 0)) 119 | 120 | class TimeExceed(Quote): 121 | pass 122 | 123 | _typesw = {0: Echo, 3: Unreach, 4: Quench, 5: Redirect, 8: Echo, 11: TimeExceed} 124 | 125 | def unpack(self, buf): 126 | dpkt.Packet.unpack(self, buf) 127 | try: 128 | self.data = self._typesw[self.type](self.data) 129 | setattr(self, self.data.__class__.__name__.lower(), self.data) 130 | except (KeyError, dpkt.UnpackError): 131 | pass 132 | 133 | def __bytes__(self): 134 | if not self.sum: 135 | self.sum = dpkt.in_cksum(dpkt.Packet.__bytes__(self)) 136 | return dpkt.Packet.__bytes__(self) 137 | 138 | 139 | def test_icmp(): 140 | s = ( 141 | b'\x03\x0a\x6b\x19\x00\x00\x00\x00\x45\x00\x00\x28\x94\x1f\x00\x00\xe3\x06\x99\xb4\x23\x2b' 142 | b'\x24\x00\xde\x8e\x84\x42\xab\xd1\x00\x50\x00\x35\xe1\x29\x20\xd9\x00\x00\x00\x22\x9b\xf0' 143 | b'\xe2\x04\x65\x6b' 144 | ) 145 | r = ICMP(s) 146 | assert bytes(r) == s 147 | 148 | # construction 149 | s = ( 150 | b'\x00\x00\x53\x87\x00\x01\x03\xd6\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e' 151 | b'\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x41\x42\x43\x44\x45\x46\x47\x48\x49' 152 | ) 153 | p = ICMP( 154 | type=0, 155 | sum=0x5387, 156 | data=ICMP.Echo( 157 | id=1, 158 | seq=0x03d6, 159 | data=b'ABCDEFGHIJKLMNOPQRSTUVWABCDEFGHI' 160 | ) 161 | ) 162 | assert bytes(p) == s 163 | 164 | # test checksum 165 | p = ICMP( 166 | type=0, 167 | data=ICMP.Echo( 168 | id=1, 169 | seq=0x03d6, 170 | data=b'ABCDEFGHIJKLMNOPQRSTUVWABCDEFGHI' 171 | ) 172 | ) 173 | assert bytes(p) == s 174 | assert p.sum == 0x5387 175 | 176 | 177 | def test_invalid_data(): 178 | from binascii import unhexlify 179 | 180 | buf = unhexlify( 181 | '01' # type (invalid entry) 182 | '00' # code 183 | '0000' # sum 184 | 185 | 'abcd' # data 186 | ) 187 | icmp = ICMP(buf) 188 | 189 | # no additional attributes have been added due to the type being invalid 190 | assert dir(icmp) == dir(ICMP()) 191 | -------------------------------------------------------------------------------- /dpkt/icmp6.py: -------------------------------------------------------------------------------- 1 | # $Id: icmp6.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Internet Control Message Protocol for IPv6.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | ICMP6_DST_UNREACH = 1 # dest unreachable, codes: 9 | ICMP6_PACKET_TOO_BIG = 2 # packet too big 10 | ICMP6_TIME_EXCEEDED = 3 # time exceeded, code: 11 | ICMP6_PARAM_PROB = 4 # ip6 header bad 12 | 13 | ICMP6_ECHO_REQUEST = 128 # echo service 14 | ICMP6_ECHO_REPLY = 129 # echo reply 15 | MLD_LISTENER_QUERY = 130 # multicast listener query 16 | MLD_LISTENER_REPORT = 131 # multicast listener report 17 | MLD_LISTENER_DONE = 132 # multicast listener done 18 | 19 | # RFC2292 decls 20 | ICMP6_MEMBERSHIP_QUERY = 130 # group membership query 21 | ICMP6_MEMBERSHIP_REPORT = 131 # group membership report 22 | ICMP6_MEMBERSHIP_REDUCTION = 132 # group membership termination 23 | 24 | ND_ROUTER_SOLICIT = 133 # router solicitation 25 | ND_ROUTER_ADVERT = 134 # router advertisement 26 | ND_NEIGHBOR_SOLICIT = 135 # neighbor solicitation 27 | ND_NEIGHBOR_ADVERT = 136 # neighbor advertisement 28 | ND_REDIRECT = 137 # redirect 29 | 30 | ICMP6_ROUTER_RENUMBERING = 138 # router renumbering 31 | 32 | ICMP6_WRUREQUEST = 139 # who are you request 33 | ICMP6_WRUREPLY = 140 # who are you reply 34 | ICMP6_FQDN_QUERY = 139 # FQDN query 35 | ICMP6_FQDN_REPLY = 140 # FQDN reply 36 | ICMP6_NI_QUERY = 139 # node information request 37 | ICMP6_NI_REPLY = 140 # node information reply 38 | 39 | ICMP6_MAXTYPE = 201 40 | 41 | 42 | class ICMP6(dpkt.Packet): 43 | """Internet Control Message Protocol for IPv6. 44 | 45 | Internet Control Message Protocol version 6 (ICMPv6) is the implementation of the Internet Control Message Protocol 46 | (ICMP) for Internet Protocol version 6 (IPv6). ICMPv6 is an integral part of IPv6 and performs error reporting 47 | and diagnostic functions. 48 | 49 | Attributes: 50 | __hdr__: Header fields of ICMPv6. 51 | type: (int): Type. Control messages are identified by the value in the type field. (1 byte) 52 | code: (int): Code. The code field gives additional context information for the message. (1 byte) 53 | sum: (int): Checksum. ICMPv6 provides a minimal level of message integrity verification. (2 bytes) 54 | """ 55 | 56 | __hdr__ = ( 57 | ('type', 'B', 0), 58 | ('code', 'B', 0), 59 | ('sum', 'H', 0) 60 | ) 61 | 62 | class Error(dpkt.Packet): 63 | __hdr__ = (('pad', 'I', 0), ) 64 | 65 | def unpack(self, buf): 66 | dpkt.Packet.unpack(self, buf) 67 | from . import ip6 68 | self.data = self.ip6 = ip6.IP6(self.data) 69 | 70 | class Unreach(Error): 71 | pass 72 | 73 | class TooBig(Error): 74 | __hdr__ = (('mtu', 'I', 1232), ) 75 | 76 | class TimeExceed(Error): 77 | pass 78 | 79 | class ParamProb(Error): 80 | __hdr__ = (('ptr', 'I', 0), ) 81 | 82 | class Echo(dpkt.Packet): 83 | __hdr__ = (('id', 'H', 0), ('seq', 'H', 0)) 84 | 85 | _typesw = {1: Unreach, 2: TooBig, 3: TimeExceed, 4: ParamProb, 128: Echo, 129: Echo} 86 | 87 | def unpack(self, buf): 88 | dpkt.Packet.unpack(self, buf) 89 | try: 90 | self.data = self._typesw[self.type](self.data) 91 | setattr(self, self.data.__class__.__name__.lower(), self.data) 92 | except (KeyError, dpkt.UnpackError): 93 | pass 94 | -------------------------------------------------------------------------------- /dpkt/igmp.py: -------------------------------------------------------------------------------- 1 | # $Id: igmp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Internet Group Management Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | 9 | class IGMP(dpkt.Packet): 10 | """Internet Group Management Protocol. 11 | 12 | TODO: Longer class information.... 13 | 14 | Attributes: 15 | __hdr__: Header fields of IGMP. 16 | TODO. 17 | """ 18 | 19 | __hdr__ = ( 20 | ('type', 'B', 0), 21 | ('maxresp', 'B', 0), 22 | ('sum', 'H', 0), 23 | ('group', '4s', b'\x00' * 4) 24 | ) 25 | 26 | def __bytes__(self): 27 | if not self.sum: 28 | self.sum = dpkt.in_cksum(dpkt.Packet.__bytes__(self)) 29 | return dpkt.Packet.__bytes__(self) 30 | 31 | 32 | def test_construction_no_sum(): 33 | igmp = IGMP() 34 | assert igmp.type == 0 35 | assert igmp.maxresp == 0 36 | assert igmp.sum == 0 37 | assert igmp.group == b'\x00' * 4 38 | 39 | assert bytes(igmp) == b'\x00\x00' + b'\xff\xff' + b'\x00' * 4 40 | 41 | 42 | def test_construction_sum_set(): 43 | igmp = IGMP(sum=1) 44 | assert igmp.type == 0 45 | assert igmp.maxresp == 0 46 | assert igmp.sum == 1 47 | assert igmp.group == b'\x00' * 4 48 | 49 | assert bytes(igmp) == b'\x00\x00\x00\x01' + b'\x00' * 4 50 | -------------------------------------------------------------------------------- /dpkt/ipip.py: -------------------------------------------------------------------------------- 1 | # Defines a copy of the IP protocol as IPIP so the protocol parsing in ip.py 2 | # can decode IPIP packets. 3 | from __future__ import absolute_import 4 | 5 | from .ip import IP as IPIP 6 | -------------------------------------------------------------------------------- /dpkt/ipx.py: -------------------------------------------------------------------------------- 1 | # $Id: ipx.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Internetwork Packet Exchange.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | IPX_HDR_LEN = 30 9 | 10 | 11 | class IPX(dpkt.Packet): 12 | """Internetwork Packet Exchange. 13 | 14 | Internetwork Packet Exchange (IPX) is the network layer protocol in the IPX/SPX protocol suite. 15 | IPX is derived from Xerox Network Systems' IDP. It also has the ability to act as a transport layer protocol. 16 | 17 | Attributes: 18 | __hdr__: Header fields of IPX. 19 | sum: (int): Checksum (2 bytes). 20 | len: (int): Packet Length (including the IPX header / 2 bytes). 21 | tc: (int): Transport Control (hop count / 1 byte). 22 | pt: (int): Packet Type (1 byte). 23 | dst: (bytes): Destination address (12 bytes). 24 | src: (bytes): Source address (12 bytes). 25 | """ 26 | 27 | __hdr__ = ( 28 | ('sum', 'H', 0xffff), 29 | ('len', 'H', IPX_HDR_LEN), 30 | ('tc', 'B', 0), 31 | ('pt', 'B', 0), 32 | ('dst', '12s', b''), 33 | ('src', '12s', b'') 34 | ) 35 | -------------------------------------------------------------------------------- /dpkt/llc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import print_function 4 | from __future__ import absolute_import 5 | 6 | import struct 7 | 8 | from . import dpkt 9 | from . import stp 10 | 11 | 12 | class LLC(dpkt.Packet): 13 | """802.2 Logical Link Control (LLC) data communication protocol. 14 | 15 | Attributes: 16 | __hdr__ = ( 17 | ('dsap', 'B', 0xaa), # Destination Service Access Point 18 | ('ssap', 'B', 0xaa), # Source Service Access Point 19 | ('ctl', 'B', 3) # Control Byte 20 | ) 21 | """ 22 | 23 | __hdr__ = ( 24 | ('dsap', 'B', 0xaa), # Destination Service Access Point 25 | ('ssap', 'B', 0xaa), # Source Service Access Point 26 | ('ctl', 'B', 3) # Control Byte 27 | ) 28 | 29 | @property 30 | def is_snap(self): 31 | return self.dsap == self.ssap == 0xaa 32 | 33 | def unpack(self, buf): 34 | from .ethernet import Ethernet, ETH_TYPE_IP, ETH_TYPE_IPX 35 | 36 | dpkt.Packet.unpack(self, buf) 37 | if self.is_snap: 38 | self.oui, self.type = struct.unpack('>IH', b'\x00' + self.data[:5]) 39 | self.data = self.data[5:] 40 | try: 41 | self.data = Ethernet.get_type(self.type)(self.data) 42 | setattr(self, self.data.__class__.__name__.lower(), self.data) 43 | except (KeyError, dpkt.UnpackError): 44 | pass 45 | else: 46 | # non-SNAP 47 | if self.dsap == 0x06: # SAP_IP 48 | self.data = self.ip = Ethernet.get_type(ETH_TYPE_IP)(self.data) 49 | elif self.dsap == 0x10 or self.dsap == 0xe0: # SAP_NETWARE{1,2} 50 | self.data = self.ipx = Ethernet.get_type(ETH_TYPE_IPX)(self.data) 51 | elif self.dsap == 0x42: # SAP_STP 52 | self.data = self.stp = stp.STP(self.data) 53 | 54 | def pack_hdr(self): 55 | buf = dpkt.Packet.pack_hdr(self) 56 | if self.is_snap: # add SNAP sublayer 57 | oui = getattr(self, 'oui', 0) 58 | _type = getattr(self, 'type', 0) 59 | if not _type and isinstance(self.data, dpkt.Packet): 60 | from .ethernet import Ethernet 61 | try: 62 | _type = Ethernet.get_type_rev(self.data.__class__) 63 | except KeyError: 64 | pass 65 | buf += struct.pack('>IH', oui, _type)[1:] 66 | return buf 67 | 68 | def __len__(self): # add 5 bytes of SNAP header if needed 69 | return self.__hdr_len__ + 5 * int(self.is_snap) + len(self.data) 70 | 71 | 72 | def test_llc(): 73 | from . import ip 74 | from . import ethernet 75 | s = (b'\xaa\xaa\x03\x00\x00\x00\x08\x00\x45\x00\x00\x28\x07\x27\x40\x00\x80\x06\x1d' 76 | b'\x39\x8d\xd4\x37\x3d\x3f\xf5\xd1\x69\xc0\x5f\x01\xbb\xb2\xd6\xef\x23\x38\x2b' 77 | b'\x4f\x08\x50\x10\x42\x04\xac\x17\x00\x00') 78 | llc_pkt = LLC(s) 79 | ip_pkt = llc_pkt.data 80 | assert isinstance(ip_pkt, ip.IP) 81 | assert llc_pkt.type == ethernet.ETH_TYPE_IP 82 | assert ip_pkt.dst == b'\x3f\xf5\xd1\x69' 83 | assert str(llc_pkt) == str(s) 84 | assert len(llc_pkt) == len(s) 85 | 86 | # construction with SNAP header 87 | llc_pkt = LLC(ssap=0xaa, dsap=0xaa, data=ip.IP(s[8:])) 88 | assert str(llc_pkt) == str(s) 89 | 90 | # no SNAP 91 | llc_pkt = LLC(ssap=6, dsap=6, data=ip.IP(s[8:])) 92 | assert isinstance(llc_pkt.data, ip.IP) 93 | assert str(llc_pkt) == str(b'\x06\x06\x03' + s[8:]) 94 | 95 | 96 | def test_unpack_sap_ip(): 97 | from binascii import unhexlify 98 | 99 | from . import ip 100 | 101 | buf_llc = unhexlify( 102 | '06' # dsap (SAP_IP) 103 | 'aa' # ssap 104 | '03' # ctl 105 | ) 106 | buf_ip = unhexlify( 107 | '45' # _v_hl 108 | '00' # tos 109 | '0014' # len 110 | '0000' # id 111 | '0000' # off 112 | '80' # ttl 113 | '06' # p 114 | 'd47e' # sum 115 | '11111111' # src 116 | '22222222' # dst 117 | ) 118 | 119 | buf = buf_llc + buf_ip 120 | llc = LLC(buf) 121 | assert isinstance(llc.data, ip.IP) 122 | 123 | 124 | def test_unpack_exception_handling(): 125 | from binascii import unhexlify 126 | 127 | buf_llc = unhexlify( 128 | 'aa' # dsap (SAP_IP) 129 | 'aa' # ssap 130 | '03' # ctl 131 | 132 | '111111' # oui 133 | '2222' # type (not valid ethertype) 134 | ) 135 | 136 | llc = LLC(buf_llc) 137 | assert not isinstance(llc.data, dpkt.Packet) 138 | 139 | 140 | def test_pack_hdr_invalid_class(): 141 | from binascii import unhexlify 142 | 143 | class InvalidClass(dpkt.Packet): 144 | __hdr__ = (('test', 'B', 0x22),) 145 | 146 | llc = LLC(dsap=0xaa, ssap=0xaa, ctl=3, oui=0x111111, data=InvalidClass()) 147 | correct = unhexlify( 148 | 'aa' # dsap 149 | 'aa' # ssap 150 | '03' # ctl 151 | 152 | '111111' # oui 153 | '0000' # type 154 | 155 | '22' # data in test class header 156 | ) 157 | assert bytes(llc) == correct 158 | -------------------------------------------------------------------------------- /dpkt/loopback.py: -------------------------------------------------------------------------------- 1 | # $Id: loopback.py 38 2007-03-17 03:33:16Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Platform-dependent loopback header.""" 4 | 5 | # https://wiki.wireshark.org/NullLoopback 6 | 7 | from __future__ import absolute_import 8 | 9 | from . import dpkt 10 | from . import ethernet 11 | from . import ip 12 | from . import ip6 13 | 14 | 15 | class Loopback(dpkt.Packet): 16 | """Platform-dependent loopback header. 17 | 18 | TODO: Longer class information.... 19 | 20 | Attributes: 21 | __hdr__: Header fields of Loopback. 22 | TODO. 23 | """ 24 | 25 | __hdr__ = (('family', 'I', 0), ) 26 | __byte_order__ = '@' 27 | 28 | def unpack(self, buf): 29 | dpkt.Packet.unpack(self, buf) 30 | if self.family in (0x02, 0x02000000): 31 | self.family = 2 32 | self.data = ip.IP(self.data) 33 | 34 | elif self.family in (0x18, 0x18000000): 35 | self.family = 24 36 | self.data = ip6.IP6(self.data) 37 | 38 | elif self.family in (0x1c, 0x1c000000): 39 | self.family = 28 40 | self.data = ip6.IP6(self.data) 41 | 42 | elif self.family in (0x1e, 0x1e000000): 43 | self.family = 30 44 | self.data = ip6.IP6(self.data) 45 | 46 | else: 47 | self.data = ethernet.Ethernet(self.data) 48 | 49 | 50 | def test_ethernet_unpack(): 51 | buf = b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x08\x00' 52 | hdr = b'\x00\x02\x00\x02' 53 | 54 | lo = Loopback(hdr + buf) 55 | assert lo.family in (0x02000200, 0x00020002) # little endian, big endian 56 | assert isinstance(lo.data, ethernet.Ethernet) 57 | assert lo.data.src == b'\x07\x08\t\n\x0b\x0c' 58 | assert lo.data.dst == b'\x01\x02\x03\x04\x05\x06' 59 | 60 | 61 | def test_ip_unpack(): 62 | buf = b'E\x00\x004\xbd\x04@\x00@\x06\x7f\xbd\x7f\x00\x00\x02\x7f\x00\x00\x01' 63 | 64 | for hdr in (b'\x00\x00\x00\x02', b'\x02\x00\x00\x00'): 65 | lo = Loopback(hdr + buf) 66 | assert lo.family == 2 67 | assert isinstance(lo.data, ip.IP) 68 | assert lo.data.src == b'\x7f\x00\x00\x02' 69 | assert lo.data.dst == b'\x7f\x00\x00\x01' 70 | 71 | 72 | def test_ip6_unpack(): 73 | import struct 74 | buf = (b'\x60\x00\x00\x00\x00\x14\x06\x38\x26\x07\xf8\xb0\x40\x0c\x0c\x03\x00\x00\x00\x00\x00\x00' 75 | b'\x00\x1a\x20\x01\x04\x70\xe5\xbf\xde\xad\x49\x57\x21\x74\xe8\x2c\x48\x87') 76 | hdr_suffix = b'\x00' * 3 77 | 78 | for family in (24, 28, 30): 79 | hdr = struct.pack('B', family) + hdr_suffix 80 | 81 | lo = Loopback(hdr + buf) 82 | assert lo.family == family 83 | assert isinstance(lo.data, ip6.IP6) 84 | assert lo.data.src == b'&\x07\xf8\xb0@\x0c\x0c\x03\x00\x00\x00\x00\x00\x00\x00\x1a' 85 | assert lo.data.dst == b' \x01\x04p\xe5\xbf\xde\xadIW!t\xe8,H\x87' 86 | -------------------------------------------------------------------------------- /dpkt/mrt.py: -------------------------------------------------------------------------------- 1 | # $Id: mrt.py 29 2007-01-26 02:29:07Z jon.oberheide $ 2 | # -*- coding: utf-8 -*- 3 | """Multi-threaded Routing Toolkit.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | from . import bgp 8 | 9 | # Multi-threaded Routing Toolkit 10 | # http://www.ietf.org/internet-drafts/draft-ietf-grow-mrt-03.txt 11 | 12 | # MRT Types 13 | NULL = 0 14 | START = 1 15 | DIE = 2 16 | I_AM_DEAD = 3 17 | PEER_DOWN = 4 18 | BGP = 5 # Deprecated by BGP4MP 19 | RIP = 6 20 | IDRP = 7 21 | RIPNG = 8 22 | BGP4PLUS = 9 # Deprecated by BGP4MP 23 | BGP4PLUS_01 = 10 # Deprecated by BGP4MP 24 | OSPF = 11 25 | TABLE_DUMP = 12 26 | BGP4MP = 16 27 | BGP4MP_ET = 17 28 | ISIS = 32 29 | ISIS_ET = 33 30 | OSPF_ET = 64 31 | 32 | # BGP4MP Subtypes 33 | BGP4MP_STATE_CHANGE = 0 34 | BGP4MP_MESSAGE = 1 35 | BGP4MP_ENTRY = 2 36 | BGP4MP_SNAPSHOT = 3 37 | BGP4MP_MESSAGE_32BIT_AS = 4 38 | 39 | # Address Family Types 40 | AFI_IPv4 = 1 41 | AFI_IPv6 = 2 42 | 43 | 44 | class MRTHeader(dpkt.Packet): 45 | __hdr__ = ( 46 | ('ts', 'I', 0), 47 | ('type', 'H', 0), 48 | ('subtype', 'H', 0), 49 | ('len', 'I', 0) 50 | ) 51 | 52 | 53 | class TableDump(dpkt.Packet): 54 | __hdr__ = ( 55 | ('view', 'H', 0), 56 | ('seq', 'H', 0), 57 | ('prefix', 'I', 0), 58 | ('prefix_len', 'B', 0), 59 | ('status', 'B', 1), 60 | ('originated_ts', 'I', 0), 61 | ('peer_ip', 'I', 0), 62 | ('peer_as', 'H', 0), 63 | ('attr_len', 'H', 0) 64 | ) 65 | 66 | def unpack(self, buf): 67 | dpkt.Packet.unpack(self, buf) 68 | plen = self.attr_len 69 | l_ = [] 70 | while plen > 0: 71 | attr = bgp.BGP.Update.Attribute(self.data) 72 | self.data = self.data[len(attr):] 73 | plen -= len(attr) 74 | l_.append(attr) 75 | self.attributes = l_ 76 | 77 | 78 | class BGP4MPMessage(dpkt.Packet): 79 | __hdr__ = ( 80 | ('src_as', 'H', 0), 81 | ('dst_as', 'H', 0), 82 | ('intf', 'H', 0), 83 | ('family', 'H', AFI_IPv4), 84 | ('src_ip', 'I', 0), 85 | ('dst_ip', 'I', 0) 86 | ) 87 | 88 | 89 | class BGP4MPMessage_32(dpkt.Packet): 90 | __hdr__ = ( 91 | ('src_as', 'I', 0), 92 | ('dst_as', 'I', 0), 93 | ('intf', 'H', 0), 94 | ('family', 'H', AFI_IPv4), 95 | ('src_ip', 'I', 0), 96 | ('dst_ip', 'I', 0) 97 | ) 98 | 99 | 100 | def test_tabledump(): 101 | from binascii import unhexlify 102 | buf_tabledump = unhexlify( 103 | '0001' # view 104 | '0002' # seq 105 | '00000003' # prefix 106 | '04' # prefix_len 107 | '05' # status 108 | '00000006' # originated_ts 109 | '00000007' # peer_ip 110 | '0008' # peer_as 111 | 112 | '0002' # attr_len 113 | ) 114 | buf_attrs = unhexlify( 115 | '01' # flags 116 | '01' # type (ORIGIN) 117 | 118 | '01' # length 119 | '02' # Origin.type (INCOMPLETE) 120 | ) 121 | buf = buf_tabledump + buf_attrs 122 | table_dump = TableDump(buf) 123 | assert table_dump.view == 1 124 | assert table_dump.seq == 2 125 | assert table_dump.prefix == 3 126 | assert table_dump.prefix_len == 4 127 | assert table_dump.status == 5 128 | assert table_dump.originated_ts == 6 129 | assert table_dump.peer_ip == 7 130 | assert table_dump.peer_as == 8 131 | assert table_dump.attr_len == 2 132 | 133 | assert len(table_dump.attributes) == 1 134 | attr = table_dump.attributes[0] 135 | assert isinstance(attr, bgp.BGP.Update.Attribute) 136 | assert isinstance(attr.data, bgp.BGP.Update.Attribute.Origin) 137 | -------------------------------------------------------------------------------- /dpkt/ntp.py: -------------------------------------------------------------------------------- 1 | # $Id: ntp.py 48 2008-05-27 17:31:15Z yardley $ 2 | # -*- coding: utf-8 -*- 3 | """Network Time Protocol.""" 4 | from __future__ import print_function 5 | 6 | from . import dpkt 7 | 8 | # NTP v4 9 | 10 | # Leap Indicator (LI) Codes 11 | NO_WARNING = 0 12 | LAST_MINUTE_61_SECONDS = 1 13 | LAST_MINUTE_59_SECONDS = 2 14 | ALARM_CONDITION = 3 15 | 16 | # Mode Codes 17 | RESERVED = 0 18 | SYMMETRIC_ACTIVE = 1 19 | SYMMETRIC_PASSIVE = 2 20 | CLIENT = 3 21 | SERVER = 4 22 | BROADCAST = 5 23 | CONTROL_MESSAGE = 6 24 | PRIVATE = 7 25 | 26 | 27 | class NTP(dpkt.Packet): 28 | """Network Time Protocol. 29 | 30 | The Network Time Protocol (NTP) is a networking protocol for clock synchronization between computer systems over 31 | packet-switched, variable-latency data networks. In operation since before 1985, NTP is one of the oldest Internet 32 | protocols in current use. NTP was designed by David L. Mills of the University of Delaware. 33 | 34 | Attributes: 35 | __hdr__: Header fields of NTP. 36 | TODO. 37 | """ 38 | 39 | __hdr__ = ( 40 | ('flags', 'B', 0), 41 | ('stratum', 'B', 0), 42 | ('interval', 'B', 0), 43 | ('precision', 'B', 0), 44 | ('delay', 'I', 0), 45 | ('dispersion', 'I', 0), 46 | ('id', '4s', 0), 47 | ('update_time', '8s', 0), 48 | ('originate_time', '8s', 0), 49 | ('receive_time', '8s', 0), 50 | ('transmit_time', '8s', 0) 51 | ) 52 | __bit_fields__ = { 53 | 'flags': ( 54 | ('li', 2), # leap indicator, 2 hi bits 55 | ('v', 3), # version, 3 bits 56 | ('mode', 3), # mode, 3 lo bits 57 | ) 58 | } 59 | 60 | 61 | __s = (b'\x24\x02\x04\xef\x00\x00\x00\x84\x00\x00\x33\x27\xc1\x02\x04\x02\xc8\x90\xec\x11\x22\xae' 62 | b'\x07\xe5\xc8\x90\xf9\xd9\xc0\x7e\x8c\xcd\xc8\x90\xf9\xd9\xda\xc5\xb0\x78\xc8\x90\xf9\xd9\xda\xc6\x8a\x93') 63 | 64 | 65 | def test_ntp_pack(): 66 | n = NTP(__s) 67 | assert (__s == bytes(n)) 68 | 69 | 70 | def test_ntp_unpack(): 71 | n = NTP(__s) 72 | assert (n.li == NO_WARNING) 73 | assert (n.v == 4) 74 | assert (n.mode == SERVER) 75 | assert (n.stratum == 2) 76 | assert (n.id == b'\xc1\x02\x04\x02') 77 | # test get/set functions 78 | n.li = ALARM_CONDITION 79 | n.v = 3 80 | n.mode = CLIENT 81 | assert (n.li == ALARM_CONDITION) 82 | assert (n.v == 3) 83 | assert (n.mode == CLIENT) 84 | -------------------------------------------------------------------------------- /dpkt/ospf.py: -------------------------------------------------------------------------------- 1 | # $Id: ospf.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Open Shortest Path First.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | AUTH_NONE = 0 9 | AUTH_PASSWORD = 1 10 | AUTH_CRYPTO = 2 11 | 12 | 13 | class OSPF(dpkt.Packet): 14 | """Open Shortest Path First. 15 | 16 | TODO: Longer class information.... 17 | 18 | Attributes: 19 | __hdr__: Header fields of OSPF. 20 | TODO. 21 | """ 22 | 23 | __hdr__ = ( 24 | ('v', 'B', 0), 25 | ('type', 'B', 0), 26 | ('len', 'H', 0), 27 | ('router', 'I', 0), 28 | ('area', 'I', 0), 29 | ('sum', 'H', 0), 30 | ('atype', 'H', 0), 31 | ('auth', '8s', b'') 32 | ) 33 | 34 | def __bytes__(self): 35 | if not self.sum: 36 | self.sum = dpkt.in_cksum(dpkt.Packet.__bytes__(self)) 37 | return dpkt.Packet.__bytes__(self) 38 | 39 | 40 | def test_creation(): 41 | ospf = OSPF() 42 | assert ospf.v == 0 43 | assert ospf.type == 0 44 | assert ospf.len == 0 45 | assert ospf.router == 0 46 | assert ospf.area == 0 47 | assert ospf.sum == 0 48 | assert ospf.atype == 0 49 | assert ospf.auth == b'' 50 | 51 | # sum is 0, so it will be recalculated 52 | assert bytes(ospf) == b''.join([ 53 | b'\x00' * 12, 54 | b'\xff\xff', 55 | b'\x00' * 10 56 | ]) 57 | 58 | ospf.sum = 0x1234 59 | # sum is not 0, so it will be used 60 | assert bytes(ospf) == b''.join([ 61 | b'\x00' * 12, 62 | b'\x12\x34', 63 | b'\x00' * 10 64 | ]) 65 | -------------------------------------------------------------------------------- /dpkt/pim.py: -------------------------------------------------------------------------------- 1 | # $Id: pim.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Protocol Independent Multicast.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | 9 | class PIM(dpkt.Packet): 10 | """Protocol Independent Multicast. 11 | 12 | Protocol Independent Multicast (PIM) is a collection of multicast routing protocols, each optimized for a different 13 | environment. There are two main PIM protocols, PIM Sparse Mode and PIM Dense Mode. A third PIM protocol, 14 | Bi-directional PIM, is less widely used. 15 | 16 | Attributes: 17 | __hdr__: Header fields of PIM. 18 | _v_type: (int): Version (4 bits) and type (4 bits). PIM version number and Message type. (1 byte) 19 | _rsvd: (int): Reserved. Always cleared to zero. (1 byte) 20 | sum: (int): Checksum. The 16-bit one's complement of the one's complement sum of the entire PIM message, 21 | excluding the data portion in the Register message.(2 bytes) 22 | """ 23 | 24 | __hdr__ = ( 25 | ('_v_type', 'B', 0x20), 26 | ('_rsvd', 'B', 0), 27 | ('sum', 'H', 0) 28 | ) 29 | __bit_fields__ = { 30 | '_v_type': ( 31 | ('v', 4), 32 | ('type', 4), 33 | ) 34 | } 35 | 36 | def __bytes__(self): 37 | if not self.sum: 38 | self.sum = dpkt.in_cksum(dpkt.Packet.__bytes__(self)) 39 | return dpkt.Packet.__bytes__(self) 40 | 41 | 42 | def test_pim(): 43 | from binascii import unhexlify 44 | buf = unhexlify( 45 | '20' # _v_type 46 | '00' # rsvd 47 | 'df93' # sum 48 | 49 | '000100020069' # data 50 | ) 51 | pimdata = PIM(buf) 52 | assert bytes(pimdata) == buf 53 | # force checksum recalculation 54 | pimdata = PIM(buf) 55 | pimdata.sum = 0 56 | assert pimdata.sum == 0 57 | assert bytes(pimdata) == buf 58 | 59 | assert pimdata.v == 2 60 | assert pimdata.type == 0 61 | 62 | # test setters 63 | buf_modified = unhexlify( 64 | '31' # _v_type 65 | '00' # rsvd 66 | 'df93' # sum 67 | 68 | '000100020069' # data 69 | ) 70 | pimdata.v = 3 71 | pimdata.type = 1 72 | assert bytes(pimdata) == buf_modified 73 | -------------------------------------------------------------------------------- /dpkt/pmap.py: -------------------------------------------------------------------------------- 1 | # $Id: pmap.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Portmap / rpcbind.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | PMAP_PROG = 100000 9 | PMAP_PROCDUMP = 4 10 | PMAP_VERS = 2 11 | 12 | 13 | class Pmap(dpkt.Packet): 14 | """Portmap / rpcbind. 15 | 16 | The port mapper (rpc.portmap or just portmap, or rpcbind) is an Open Network Computing Remote Procedure 17 | Call (ONC RPC) service that runs on network nodes that provide other ONC RPC services. The port mapper service 18 | always uses TCP or UDP port 111; a fixed port is required for it, as a client would not be able to get the 19 | port number for the port mapper service from the port mapper itself. 20 | 21 | Attributes: 22 | __hdr__: Header fields of Pmap. 23 | prog: (int) Program. (4 bytes) 24 | vers: (int) Version. (4 bytes) 25 | prot: (int) Protocol. (4 bytes) 26 | port: (int) Port. (4 bytes) 27 | """ 28 | 29 | __hdr__ = ( 30 | ('prog', 'I', 0), 31 | ('vers', 'I', 0), 32 | ('prot', 'I', 0), 33 | ('port', 'I', 0), 34 | ) 35 | -------------------------------------------------------------------------------- /dpkt/ppp.py: -------------------------------------------------------------------------------- 1 | # $Id: ppp.py 65 2010-03-26 02:53:51Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Point-to-Point Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | import struct 7 | 8 | from . import dpkt 9 | 10 | # XXX - finish later 11 | 12 | # http://www.iana.org/assignments/ppp-numbers 13 | PPP_IP = 0x21 # Internet Protocol 14 | PPP_IP6 = 0x57 # Internet Protocol v6 15 | 16 | # Protocol field compression 17 | PFC_BIT = 0x01 18 | 19 | 20 | class PPP(dpkt.Packet): 21 | """Point-to-Point Protocol. 22 | 23 | Point-to-Point Protocol (PPP) is a data link layer (layer 2) communication protocol between two routers directly 24 | without any host or any other networking in between. It can provide connection authentication, transmission 25 | encryption and data compression. 26 | 27 | Note: This class is subclassed in PPPoE 28 | 29 | Attributes: 30 | __hdr__: Header fields of PPP. 31 | addr: (int): Address. 0xFF, standard broadcast address. (1 byte) 32 | cntrl: (int): Control. 0x03, unnumbered data. (1 byte) 33 | p: (int): Protocol. PPP ID of embedded data. (1 byte) 34 | """ 35 | 36 | __hdr__ = ( 37 | ('addr', 'B', 0xff), 38 | ('cntrl', 'B', 3), 39 | ('p', 'B', PPP_IP), 40 | ) 41 | _protosw = {} 42 | 43 | @classmethod 44 | def set_p(cls, p, pktclass): 45 | cls._protosw[p] = pktclass 46 | 47 | @classmethod 48 | def get_p(cls, p): 49 | return cls._protosw[p] 50 | 51 | def unpack(self, buf): 52 | dpkt.Packet.unpack(self, buf) 53 | if self.p & PFC_BIT == 0: 54 | try: 55 | self.p = struct.unpack('>H', buf[2:4])[0] 56 | except struct.error: 57 | raise dpkt.NeedData 58 | self.data = self.data[1:] 59 | try: 60 | self.data = self._protosw[self.p](self.data) 61 | setattr(self, self.data.__class__.__name__.lower(), self.data) 62 | except (KeyError, struct.error, dpkt.UnpackError): 63 | pass 64 | 65 | def pack_hdr(self): 66 | try: 67 | if self.p > 0xff: 68 | return struct.pack('>BBH', self.addr, self.cntrl, self.p) 69 | return dpkt.Packet.pack_hdr(self) 70 | except struct.error as e: 71 | raise dpkt.PackError(str(e)) 72 | 73 | 74 | def __load_protos(): 75 | g = globals() 76 | for k, v in g.items(): 77 | if k.startswith('PPP_'): 78 | name = k[4:] 79 | modname = name.lower() 80 | try: 81 | mod = __import__(modname, g, level=1) 82 | PPP.set_p(v, getattr(mod, name)) 83 | except (ImportError, AttributeError): 84 | continue 85 | 86 | 87 | def _mod_init(): 88 | """Post-initialization called when all dpkt modules are fully loaded""" 89 | if not PPP._protosw: 90 | __load_protos() 91 | 92 | 93 | def test_ppp(): 94 | # Test protocol compression 95 | s = b"\xff\x03\x21" 96 | p = PPP(s) 97 | assert p.p == 0x21 98 | 99 | s = b"\xff\x03\x00\x21" 100 | p = PPP(s) 101 | assert p.p == 0x21 102 | 103 | 104 | def test_ppp_short(): 105 | s = b"\xff\x03\x00" 106 | 107 | import pytest 108 | pytest.raises(dpkt.NeedData, PPP, s) 109 | 110 | 111 | def test_packing(): 112 | p = PPP() 113 | assert p.pack_hdr() == b"\xff\x03\x21" 114 | 115 | p.p = 0xc021 # LCP 116 | assert p.pack_hdr() == b"\xff\x03\xc0\x21" 117 | 118 | 119 | def test_ppp_classmethods(): 120 | import pytest 121 | 122 | class TestProto(dpkt.Packet): 123 | pass 124 | 125 | proto_number = 123 126 | 127 | # asserting that this proto is not currently added 128 | with pytest.raises(KeyError): 129 | PPP.get_p(proto_number) 130 | 131 | PPP.set_p(proto_number, TestProto) 132 | 133 | assert PPP.get_p(proto_number) == TestProto 134 | 135 | # we need to reset the class, or impact other tests 136 | del PPP._protosw[proto_number] 137 | 138 | 139 | def test_unpacking_exceptions(): 140 | from dpkt import ip 141 | 142 | from binascii import unhexlify 143 | buf_ppp = unhexlify( 144 | 'ff' # addr 145 | '03' # cntrl 146 | '21' # p (PPP_IP) 147 | ) 148 | buf_ip = unhexlify( 149 | '45' # _v_hl 150 | '00' # tos 151 | '0014' # len 152 | '0000' # id 153 | '0000' # off 154 | '80' # ttl 155 | '06' # p 156 | 'd47e' # sum 157 | '11111111' # src 158 | '22222222' # dst 159 | ) 160 | 161 | buf = buf_ppp + buf_ip 162 | ppp = PPP(buf) 163 | assert hasattr(ppp, 'ip') 164 | assert isinstance(ppp.data, ip.IP) 165 | assert bytes(ppp) == buf 166 | 167 | 168 | def test_ppp_packing_error(): 169 | import pytest 170 | 171 | # addr is a 1-byte field, so this will overflow when packing 172 | ppp = PPP(p=257, addr=1234) 173 | with pytest.raises(dpkt.PackError): 174 | ppp.pack_hdr() 175 | 176 | 177 | def test_proto_loading(): 178 | # test that failure to load protocol handlers isn't catastrophic 179 | standard_protos = PPP._protosw 180 | # delete existing protos 181 | PPP._protosw = {} 182 | assert not PPP._protosw 183 | 184 | # inject a new global variable to be picked up 185 | globals()['PPP_NON_EXISTENT_PROTO'] = "FAIL" 186 | _mod_init() 187 | # we should get the same answer as if NON_EXISTENT_PROTO didn't exist 188 | assert PPP._protosw == standard_protos 189 | -------------------------------------------------------------------------------- /dpkt/pppoe.py: -------------------------------------------------------------------------------- 1 | # $Id: pppoe.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """PPP-over-Ethernet.""" 4 | from __future__ import absolute_import 5 | 6 | import struct 7 | import codecs 8 | 9 | from . import dpkt 10 | from . import ppp 11 | 12 | # RFC 2516 codes 13 | PPPoE_PADI = 0x09 14 | PPPoE_PADO = 0x07 15 | PPPoE_PADR = 0x19 16 | PPPoE_PADS = 0x65 17 | PPPoE_PADT = 0xA7 18 | PPPoE_SESSION = 0x00 19 | 20 | 21 | class PPPoE(dpkt.Packet): 22 | """PPP-over-Ethernet. 23 | 24 | The Point-to-Point Protocol over Ethernet (PPPoE) is a network protocol for encapsulating Point-to-Point Protocol 25 | (PPP) frames inside Ethernet frames. It appeared in 1999, in the context of the boom of DSL as the solution for 26 | tunneling packets over the DSL connection to the ISP's IP network, and from there to the rest of the Internet. 27 | 28 | Attributes: 29 | __hdr__: Header fields of PPPoE. 30 | _v_type: 31 | v: (int): Version (4 bits) 32 | type: (int): Type (4 bits) 33 | code: (int): Code. (1 byte) 34 | session: (int): Session ID. (2 bytes) 35 | len: (int): Payload length. (2 bytes) 36 | """ 37 | 38 | __hdr__ = ( 39 | ('_v_type', 'B', 0x11), 40 | ('code', 'B', 0), 41 | ('session', 'H', 0), 42 | ('len', 'H', 0) # payload length 43 | ) 44 | __bit_fields__ = { 45 | '_v_type': ( 46 | ('v', 4), 47 | ('type', 4), 48 | ) 49 | } 50 | 51 | def unpack(self, buf): 52 | dpkt.Packet.unpack(self, buf) 53 | try: 54 | if self.code == 0: 55 | # We need to use the pppoe.PPP header here, because PPPoE 56 | # doesn't do the normal encapsulation. 57 | self.data = self.ppp = PPP(self.data) 58 | except dpkt.UnpackError: 59 | pass 60 | 61 | 62 | class PPP(ppp.PPP): 63 | # Light version for protocols without the usual encapsulation, for PPPoE 64 | __hdr__ = ( 65 | # Usuaully two-bytes, but while protocol compression is not recommended, it is supported 66 | ('p', 'B', ppp.PPP_IP), 67 | ) 68 | 69 | def unpack(self, buf): 70 | dpkt.Packet.unpack(self, buf) 71 | if self.p & ppp.PFC_BIT == 0: 72 | try: 73 | self.p = struct.unpack('>H', buf[:2])[0] 74 | except struct.error: 75 | raise dpkt.NeedData 76 | self.data = self.data[1:] 77 | try: 78 | self.data = self._protosw[self.p](self.data) 79 | setattr(self, self.data.__class__.__name__.lower(), self.data) 80 | except (KeyError, struct.error, dpkt.UnpackError): 81 | pass 82 | 83 | def pack_hdr(self): 84 | try: 85 | # Protocol compression is *not* recommended (RFC2516), but we do it anyway 86 | if self.p > 0xff: 87 | return struct.pack('>H', self.p) 88 | return dpkt.Packet.pack_hdr(self) 89 | except struct.error as e: 90 | raise dpkt.PackError(str(e)) 91 | 92 | 93 | def test_pppoe_discovery(): 94 | s = ("11070000002801010000010300046413" 95 | "85180102000442524153010400103d0f" 96 | "0587062484f2df32b9ddfd77bd5b") 97 | s = codecs.decode(s, 'hex') 98 | p = PPPoE(s) 99 | 100 | assert p.code == PPPoE_PADO 101 | assert p.v == 1 102 | assert p.type == 1 103 | 104 | s = ("11190000002801010000010300046413" 105 | "85180102000442524153010400103d0f" 106 | "0587062484f2df32b9ddfd77bd5b") 107 | s = codecs.decode(s, 'hex') 108 | p = PPPoE(s) 109 | 110 | assert p.code == PPPoE_PADR 111 | 112 | assert p.pack_hdr() == s[:6] 113 | 114 | 115 | def test_pppoe_session(): 116 | s = "11000011000cc0210101000a050605fcd459" 117 | s = codecs.decode(s, 'hex') 118 | p = PPPoE(s) 119 | 120 | assert p.code == PPPoE_SESSION 121 | assert isinstance(p.ppp, PPP) 122 | assert p.data.p == 0xc021 # LCP 123 | assert len(p.data.data) == 10 124 | 125 | assert p.data.pack_hdr() == b"\xc0\x21" 126 | 127 | s = ("110000110066005760000000003c3a40fc000000000000000000000000000001" 128 | "fc0000000002010000000000000100018100bf291f9700010102030405060708" 129 | "090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728" 130 | "292a2b2c2d2e2f3031323334") 131 | s = codecs.decode(s, 'hex') 132 | p = PPPoE(s) 133 | assert p.code == PPPoE_SESSION 134 | assert isinstance(p.ppp, PPP) 135 | assert p.data.p == ppp.PPP_IP6 136 | assert p.data.data.p == 58 # ICMPv6 137 | 138 | assert p.ppp.pack_hdr() == b"\x57" 139 | 140 | 141 | def test_ppp_packing(): 142 | p = PPP() 143 | assert p.pack_hdr() == b"\x21" 144 | 145 | p.p = 0xc021 # LCP 146 | assert p.pack_hdr() == b"\xc0\x21" 147 | 148 | 149 | def test_ppp_short(): 150 | import pytest 151 | pytest.raises(dpkt.NeedData, PPP, b"\x00") 152 | 153 | 154 | def test_pppoe_properties(): 155 | pppoe = PPPoE() 156 | assert pppoe.v == 1 157 | pppoe.v = 7 158 | assert pppoe.v == 7 159 | 160 | assert pppoe.type == 1 161 | pppoe.type = 5 162 | assert pppoe.type == 5 163 | 164 | 165 | def test_pppoe_unpack_error(): 166 | from binascii import unhexlify 167 | buf = unhexlify( 168 | "11" # v/type 169 | "00" # code 170 | "0011" # session 171 | "0066" # len 172 | 173 | "00" # data 174 | ) 175 | # this initialization swallows the UnpackError raised 176 | pppoe = PPPoE(buf) 177 | # unparsed data is still available 178 | assert pppoe.data == b'\x00' 179 | 180 | 181 | def test_ppp_pack_hdr(): 182 | import pytest 183 | from binascii import unhexlify 184 | 185 | buf = unhexlify( 186 | '01' # protocol, with compression bit set 187 | 188 | 'ff' # incomplete data 189 | ) 190 | ppp = PPP(buf) 191 | ppp.p = 1234567 192 | with pytest.raises(dpkt.PackError): 193 | ppp.pack_hdr() 194 | 195 | 196 | # XXX - TODO TLVs, etc. 197 | -------------------------------------------------------------------------------- /dpkt/qq.py: -------------------------------------------------------------------------------- 1 | # $Id: qq.py 48 2008-05-27 17:31:15Z yardley $ 2 | # -*- coding: utf-8 -*- 3 | from __future__ import absolute_import 4 | 5 | from .dpkt import Packet 6 | 7 | 8 | # header_type 9 | QQ_HEADER_BASIC_FAMILY = 0x02 10 | QQ_HEADER_P2P_FAMILY = 0x00 11 | QQ_HEADER_03_FAMILY = 0x03 12 | QQ_HEADER_04_FAMILY = 0x04 13 | QQ_HEADER_05_FAMILY = 0x05 14 | 15 | header_type_str = [ 16 | "QQ_HEADER_P2P_FAMILY", 17 | "Unknown Type", 18 | "QQ_HEADER_03_FAMILY", 19 | "QQ_HEADER_04_FAMILY", 20 | "QQ_HEADER_05_FAMILY", 21 | ] 22 | 23 | # command 24 | QQ_CMD_LOGOUT = 0x0001 25 | QQ_CMD_KEEP_ALIVE = 0x0002 26 | QQ_CMD_MODIFY_INFO = 0x0004 27 | QQ_CMD_SEARCH_USER = 0x0005 28 | QQ_CMD_GET_USER_INFO = 0x0006 29 | QQ_CMD_ADD_FRIEND = 0x0009 30 | QQ_CMD_DELETE_FRIEND = 0x000A 31 | QQ_CMD_ADD_FRIEND_AUTH = 0x000B 32 | QQ_CMD_CHANGE_STATUS = 0x000D 33 | QQ_CMD_ACK_SYS_MSG = 0x0012 34 | QQ_CMD_SEND_IM = 0x0016 35 | QQ_CMD_RECV_IM = 0x0017 36 | QQ_CMD_REMOVE_SELF = 0x001C 37 | QQ_CMD_REQUEST_KEY = 0x001D 38 | QQ_CMD_LOGIN = 0x0022 39 | QQ_CMD_GET_FRIEND_LIST = 0x0026 40 | QQ_CMD_GET_ONLINE_OP = 0x0027 41 | QQ_CMD_SEND_SMS = 0x002D 42 | QQ_CMD_CLUSTER_CMD = 0x0030 43 | QQ_CMD_TEST = 0x0031 44 | QQ_CMD_GROUP_DATA_OP = 0x003C 45 | QQ_CMD_UPLOAD_GROUP_FRIEND = 0x003D 46 | QQ_CMD_FRIEND_DATA_OP = 0x003E 47 | QQ_CMD_DOWNLOAD_GROUP_FRIEND = 0x0058 48 | QQ_CMD_FRIEND_LEVEL_OP = 0x005C 49 | QQ_CMD_PRIVACY_DATA_OP = 0x005E 50 | QQ_CMD_CLUSTER_DATA_OP = 0x005F 51 | QQ_CMD_ADVANCED_SEARCH = 0x0061 52 | QQ_CMD_REQUEST_LOGIN_TOKEN = 0x0062 53 | QQ_CMD_USER_PROPERTY_OP = 0x0065 54 | QQ_CMD_TEMP_SESSION_OP = 0x0066 55 | QQ_CMD_SIGNATURE_OP = 0x0067 56 | QQ_CMD_RECV_MSG_SYS = 0x0080 57 | QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS = 0x0081 58 | QQ_CMD_WEATHER_OP = 0x00A6 59 | QQ_CMD_ADD_FRIEND_EX = 0x00A7 60 | QQ_CMD_AUTHORIZE = 0X00A8 61 | QQ_CMD_UNKNOWN = 0xFFFF 62 | QQ_SUB_CMD_SEARCH_ME_BY_QQ_ONLY = 0x03 63 | QQ_SUB_CMD_SHARE_GEOGRAPHY = 0x04 64 | QQ_SUB_CMD_GET_FRIEND_LEVEL = 0x02 65 | QQ_SUB_CMD_GET_CLUSTER_ONLINE_MEMBER = 0x01 66 | QQ_05_CMD_REQUEST_AGENT = 0x0021 67 | QQ_05_CMD_REQUEST_FACE = 0x0022 68 | QQ_05_CMD_TRANSFER = 0x0023 69 | QQ_05_CMD_REQUEST_BEGIN = 0x0026 70 | QQ_CLUSTER_CMD_CREATE_CLUSTER = 0x01 71 | QQ_CLUSTER_CMD_MODIFY_MEMBER = 0x02 72 | QQ_CLUSTER_CMD_MODIFY_CLUSTER_INFO = 0x03 73 | QQ_CLUSTER_CMD_GET_CLUSTER_INFO = 0x04 74 | QQ_CLUSTER_CMD_ACTIVATE_CLUSTER = 0x05 75 | QQ_CLUSTER_CMD_SEARCH_CLUSTER = 0x06 76 | QQ_CLUSTER_CMD_JOIN_CLUSTER = 0x07 77 | QQ_CLUSTER_CMD_JOIN_CLUSTER_AUTH = 0x08 78 | QQ_CLUSTER_CMD_EXIT_CLUSTER = 0x09 79 | QQ_CLUSTER_CMD_SEND_IM = 0x0A 80 | QQ_CLUSTER_CMD_GET_ONLINE_MEMBER = 0x0B 81 | QQ_CLUSTER_CMD_GET_MEMBER_INFO = 0x0C 82 | QQ_CLUSTER_CMD_MODIFY_CARD = 0x0E 83 | QQ_CLUSTER_CMD_GET_CARD_BATCH = 0x0F 84 | QQ_CLUSTER_CMD_GET_CARD = 0x10 85 | QQ_CLUSTER_CMD_COMMIT_ORGANIZATION = 0x11 86 | QQ_CLUSTER_CMD_UPDATE_ORGANIZATION = 0x12 87 | QQ_CLUSTER_CMD_COMMIT_MEMBER_ORGANIZATION = 0x13 88 | QQ_CLUSTER_CMD_GET_VERSION_ID = 0x19 89 | QQ_CLUSTER_CMD_SEND_IM_EX = 0x1A 90 | QQ_CLUSTER_CMD_SET_ROLE = 0x1B 91 | QQ_CLUSTER_CMD_TRANSFER_ROLE = 0x1C 92 | QQ_CLUSTER_CMD_CREATE_TEMP = 0x30 93 | QQ_CLUSTER_CMD_MODIFY_TEMP_MEMBER = 0x31 94 | QQ_CLUSTER_CMD_EXIT_TEMP = 0x32 95 | QQ_CLUSTER_CMD_GET_TEMP_INFO = 0x33 96 | QQ_CLUSTER_CMD_MODIFY_TEMP_INFO = 0x34 97 | QQ_CLUSTER_CMD_SEND_TEMP_IM = 0x35 98 | QQ_CLUSTER_CMD_SUB_CLUSTER_OP = 0x36 99 | QQ_CLUSTER_CMD_ACTIVATE_TEMP = 0x37 100 | 101 | QQ_CLUSTER_SUB_CMD_ADD_MEMBER = 0x01 102 | QQ_CLUSTER_SUB_CMD_REMOVE_MEMBER = 0x02 103 | QQ_CLUSTER_SUB_CMD_GET_SUBJECT_LIST = 0x02 104 | QQ_CLUSTER_SUB_CMD_GET_DIALOG_LIST = 0x01 105 | 106 | QQ_SUB_CMD_GET_ONLINE_FRIEND = 0x2 107 | QQ_SUB_CMD_GET_ONLINE_SERVICE = 0x3 108 | QQ_SUB_CMD_UPLOAD_GROUP_NAME = 0x2 109 | QQ_SUB_CMD_DOWNLOAD_GROUP_NAME = 0x1 110 | QQ_SUB_CMD_SEND_TEMP_SESSION_IM = 0x01 111 | QQ_SUB_CMD_BATCH_DOWNLOAD_FRIEND_REMARK = 0x0 112 | QQ_SUB_CMD_UPLOAD_FRIEND_REMARK = 0x1 113 | QQ_SUB_CMD_REMOVE_FRIEND_FROM_LIST = 0x2 114 | QQ_SUB_CMD_DOWNLOAD_FRIEND_REMARK = 0x3 115 | QQ_SUB_CMD_MODIFY_SIGNATURE = 0x01 116 | QQ_SUB_CMD_DELETE_SIGNATURE = 0x02 117 | QQ_SUB_CMD_GET_SIGNATURE = 0x03 118 | QQ_SUB_CMD_GET_USER_PROPERTY = 0x01 119 | QQ_SUB_CMD_GET_WEATHER = 0x01 120 | 121 | QQ_FILE_CMD_HEART_BEAT = 0x0001 122 | QQ_FILE_CMD_HEART_BEAT_ACK = 0x0002 123 | QQ_FILE_CMD_TRANSFER_FINISHED = 0x0003 124 | QQ_FILE_CMD_FILE_OP = 0x0007 125 | QQ_FILE_CMD_FILE_OP_ACK = 0x0008 126 | QQ_FILE_CMD_SENDER_SAY_HELLO = 0x0031 127 | QQ_FILE_CMD_SENDER_SAY_HELLO_ACK = 0x0032 128 | QQ_FILE_CMD_RECEIVER_SAY_HELLO = 0x0033 129 | QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK = 0x0034 130 | QQ_FILE_CMD_NOTIFY_IP_ACK = 0x003C 131 | QQ_FILE_CMD_PING = 0x003D 132 | QQ_FILE_CMD_PONG = 0x003E 133 | QQ_FILE_CMD_YES_I_AM_BEHIND_FIREWALL = 0x0040 134 | QQ_FILE_CMD_REQUEST_AGENT = 0x0001 135 | QQ_FILE_CMD_CHECK_IN = 0x0002 136 | QQ_FILE_CMD_FORWARD = 0x0003 137 | QQ_FILE_CMD_FORWARD_FINISHED = 0x0004 138 | QQ_FILE_CMD_IT_IS_TIME = 0x0005 139 | QQ_FILE_CMD_I_AM_READY = 0x0006 140 | 141 | command_str = { 142 | 0x0001: "QQ_CMD_LOGOUT", 143 | 0x0002: "QQ_CMD_KEEP_ALIVE", 144 | 0x0004: "QQ_CMD_MODIFY_INFO", 145 | 0x0005: "QQ_CMD_SEARCH_USER", 146 | 0x0006: "QQ_CMD_GET_USER_INFO", 147 | 0x0009: "QQ_CMD_ADD_FRIEND", 148 | 0x000A: "QQ_CMD_DELETE_FRIEND", 149 | 0x000B: "QQ_CMD_ADD_FRIEND_AUTH", 150 | 0x000D: "QQ_CMD_CHANGE_STATUS", 151 | 0x0012: "QQ_CMD_ACK_SYS_MSG", 152 | 0x0016: "QQ_CMD_SEND_IM", 153 | 0x0017: "QQ_CMD_RECV_IM", 154 | 0x001C: "QQ_CMD_REMOVE_SELF", 155 | 0x001D: "QQ_CMD_REQUEST_KEY", 156 | 0x0022: "QQ_CMD_LOGIN", 157 | 0x0026: "QQ_CMD_GET_FRIEND_LIST", 158 | 0x0027: "QQ_CMD_GET_ONLINE_OP", 159 | 0x002D: "QQ_CMD_SEND_SMS", 160 | 0x0030: "QQ_CMD_CLUSTER_CMD", 161 | 0x0031: "QQ_CMD_TEST", 162 | 0x003C: "QQ_CMD_GROUP_DATA_OP", 163 | 0x003D: "QQ_CMD_UPLOAD_GROUP_FRIEND", 164 | 0x003E: "QQ_CMD_FRIEND_DATA_OP", 165 | 0x0058: "QQ_CMD_DOWNLOAD_GROUP_FRIEND", 166 | 0x005C: "QQ_CMD_FRIEND_LEVEL_OP", 167 | 0x005E: "QQ_CMD_PRIVACY_DATA_OP", 168 | 0x005F: "QQ_CMD_CLUSTER_DATA_OP", 169 | 0x0061: "QQ_CMD_ADVANCED_SEARCH", 170 | 0x0062: "QQ_CMD_REQUEST_LOGIN_TOKEN", 171 | 0x0065: "QQ_CMD_USER_PROPERTY_OP", 172 | 0x0066: "QQ_CMD_TEMP_SESSION_OP", 173 | 0x0067: "QQ_CMD_SIGNATURE_OP", 174 | 0x0080: "QQ_CMD_RECV_MSG_SYS", 175 | 0x0081: "QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS", 176 | 0x00A6: "QQ_CMD_WEATHER_OP", 177 | 0x00A7: "QQ_CMD_ADD_FRIEND_EX", 178 | 0x00A8: "QQ_CMD_AUTHORIZE", 179 | 0xFFFF: "QQ_CMD_UNKNOWN", 180 | 0x0021: "_CMD_REQUEST_AGENT", 181 | # 0x0022: "_CMD_REQUEST_FACE", # FIXME - dup dict key 182 | 0x0023: "_CMD_TRANSFER", 183 | # 0x0026: "_CMD_REQUEST_BEGIN", # FIXME - dup dict key 184 | } 185 | 186 | 187 | class QQBasicPacket(Packet): 188 | __hdr__ = ( 189 | ('header_type', 'B', 2), 190 | ('source', 'H', 0), 191 | ('command', 'H', 0), 192 | ('sequence', 'H', 0), 193 | ('qqNum', 'L', 0), 194 | ) 195 | 196 | 197 | class QQ3Packet(Packet): 198 | __hdr__ = ( 199 | ('header_type', 'B', 3), 200 | ('command', 'B', 0), 201 | ('sequence', 'H', 0), 202 | ('unknown1', 'L', 0), 203 | ('unknown2', 'L', 0), 204 | ('unknown3', 'L', 0), 205 | ('unknown4', 'L', 0), 206 | ('unknown5', 'L', 0), 207 | ('unknown6', 'L', 0), 208 | ('unknown7', 'L', 0), 209 | ('unknown8', 'L', 0), 210 | ('unknown9', 'L', 0), 211 | ('unknown10', 'B', 1), 212 | ('unknown11', 'B', 0), 213 | ('unknown12', 'B', 0), 214 | ('source', 'H', 0), 215 | ('unknown13', 'B', 0), 216 | ) 217 | 218 | 219 | class QQ5Packet(Packet): 220 | __hdr__ = ( 221 | ('header_type', 'B', 5), 222 | ('source', 'H', 0), 223 | ('unknown', 'H', 0), 224 | ('command', 'H', 0), 225 | ('sequence', 'H', 0), 226 | ('qqNum', 'L', 0), 227 | ) 228 | -------------------------------------------------------------------------------- /dpkt/radius.py: -------------------------------------------------------------------------------- 1 | # $Id: radius.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Remote Authentication Dial-In User Service.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | from .compat import compat_ord 8 | 9 | # http://www.untruth.org/~josh/security/radius/radius-auth.html 10 | # RFC 2865 11 | 12 | 13 | class RADIUS(dpkt.Packet): 14 | """Remote Authentication Dial-In User Service. 15 | 16 | Remote Authentication Dial-In User Service (RADIUS) is a networking protocol that provides centralized 17 | authentication, authorization, and accounting (AAA) management for users who connect and use a network service. 18 | RADIUS was developed by Livingston Enterprises in 1991 as an access server authentication and accounting protocol. 19 | It was later brought into IEEE 802 and IETF standards. 20 | 21 | Attributes: 22 | __hdr__: Header fields of RADIUS. 23 | code: (int): Code. (1 byte) 24 | id: (int): ID (1 byte) 25 | len: (int): Length (2 bytes) 26 | auth: (int): Authentication (16 bytes) 27 | """ 28 | 29 | __hdr__ = ( 30 | ('code', 'B', 0), 31 | ('id', 'B', 0), 32 | ('len', 'H', 4), 33 | ('auth', '16s', b'') 34 | ) 35 | attrs = b'' 36 | 37 | def unpack(self, buf): 38 | dpkt.Packet.unpack(self, buf) 39 | self.attrs = parse_attrs(self.data) 40 | self.data = b'' 41 | 42 | 43 | def parse_attrs(buf): 44 | """Parse attributes buffer into a list of (type, data) tuples.""" 45 | attrs = [] 46 | while buf: 47 | t = compat_ord(buf[0]) 48 | l_ = compat_ord(buf[1]) 49 | if l_ < 2: 50 | break 51 | d, buf = buf[2:l_], buf[l_:] 52 | attrs.append((t, d)) 53 | return attrs 54 | 55 | 56 | # Codes 57 | RADIUS_ACCESS_REQUEST = 1 58 | RADIUS_ACCESS_ACCEPT = 2 59 | RADIUS_ACCESS_REJECT = 3 60 | RADIUS_ACCT_REQUEST = 4 61 | RADIUS_ACCT_RESPONSE = 5 62 | RADIUS_ACCT_STATUS = 6 63 | RADIUS_ACCESS_CHALLENGE = 11 64 | 65 | # Attributes 66 | RADIUS_USER_NAME = 1 67 | RADIUS_USER_PASSWORD = 2 68 | RADIUS_CHAP_PASSWORD = 3 69 | RADIUS_NAS_IP_ADDR = 4 70 | RADIUS_NAS_PORT = 5 71 | RADIUS_SERVICE_TYPE = 6 72 | RADIUS_FRAMED_PROTOCOL = 7 73 | RADIUS_FRAMED_IP_ADDR = 8 74 | RADIUS_FRAMED_IP_NETMASK = 9 75 | RADIUS_FRAMED_ROUTING = 10 76 | RADIUS_FILTER_ID = 11 77 | RADIUS_FRAMED_MTU = 12 78 | RADIUS_FRAMED_COMPRESSION = 13 79 | RADIUS_LOGIN_IP_HOST = 14 80 | RADIUS_LOGIN_SERVICE = 15 81 | RADIUS_LOGIN_TCP_PORT = 16 82 | # unassigned 83 | RADIUS_REPLY_MESSAGE = 18 84 | RADIUS_CALLBACK_NUMBER = 19 85 | RADIUS_CALLBACK_ID = 20 86 | # unassigned 87 | RADIUS_FRAMED_ROUTE = 22 88 | RADIUS_FRAMED_IPX_NETWORK = 23 89 | RADIUS_STATE = 24 90 | RADIUS_CLASS = 25 91 | RADIUS_VENDOR_SPECIFIC = 26 92 | RADIUS_SESSION_TIMEOUT = 27 93 | RADIUS_IDLE_TIMEOUT = 28 94 | RADIUS_TERMINATION_ACTION = 29 95 | RADIUS_CALLED_STATION_ID = 30 96 | RADIUS_CALLING_STATION_ID = 31 97 | RADIUS_NAS_ID = 32 98 | RADIUS_PROXY_STATE = 33 99 | RADIUS_LOGIN_LAT_SERVICE = 34 100 | RADIUS_LOGIN_LAT_NODE = 35 101 | RADIUS_LOGIN_LAT_GROUP = 36 102 | RADIUS_FRAMED_ATALK_LINK = 37 103 | RADIUS_FRAMED_ATALK_NETWORK = 38 104 | RADIUS_FRAMED_ATALK_ZONE = 39 105 | # 40-59 reserved for accounting 106 | RADIUS_CHAP_CHALLENGE = 60 107 | RADIUS_NAS_PORT_TYPE = 61 108 | RADIUS_PORT_LIMIT = 62 109 | RADIUS_LOGIN_LAT_PORT = 63 110 | 111 | 112 | def test_parse_attrs(): 113 | from binascii import unhexlify 114 | buf = unhexlify( 115 | '01' # type (RADIUS_USER_NAME) 116 | '06' # end of attribute value 117 | '75736572' # value ('user') 118 | 119 | '00' 120 | '00' 121 | ) 122 | 123 | attrs = parse_attrs(buf) 124 | assert len(attrs) == 1 125 | 126 | type0, value0 = attrs[0] 127 | assert type0 == RADIUS_USER_NAME 128 | assert value0 == b'user' 129 | 130 | 131 | def test_parse_multiple_attrs(): 132 | from binascii import unhexlify 133 | buf = unhexlify( 134 | '01' # type (RADIUS_USER_NAME) 135 | '06' # end of attribute value 136 | '75736572' # value ('user') 137 | 138 | '02' # type (RADIUS_USER_PASSWORD) 139 | '0a' # end of attribute value 140 | '70617373776f7264' # value ('password') 141 | ) 142 | 143 | attrs = parse_attrs(buf) 144 | assert len(attrs) == 2 145 | 146 | type0, value0 = attrs[0] 147 | assert type0 == RADIUS_USER_NAME 148 | assert value0 == b'user' 149 | 150 | type1, value1 = attrs[1] 151 | assert type1 == RADIUS_USER_PASSWORD 152 | assert value1 == b'password' 153 | 154 | 155 | def test_radius_unpacking(): 156 | from binascii import unhexlify 157 | buf_attrs = unhexlify( 158 | '01' # type (RADIUS_USER_NAME) 159 | '06' # end of attribute value 160 | '75736572' # value ('user') 161 | ) 162 | buf_radius_header = unhexlify( 163 | '01' # code 164 | '34' # id 165 | '1234' # len 166 | '0123456789abcdef' # auth 167 | '0123456789abcdef' # auth 168 | ) 169 | buf = buf_radius_header + buf_attrs 170 | radius = RADIUS(buf) 171 | assert len(radius.attrs) == 1 172 | name0, value0 = radius.attrs[0] 173 | assert name0 == 1 174 | assert value0 == b'user' 175 | -------------------------------------------------------------------------------- /dpkt/rfb.py: -------------------------------------------------------------------------------- 1 | # $Id: rfb.py 47 2008-05-27 02:10:00Z jon.oberheide $ 2 | # -*- coding: utf-8 -*- 3 | """Remote Framebuffer Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | # Remote Framebuffer Protocol 9 | # http://www.realvnc.com/docs/rfbproto.pdf 10 | 11 | # Client to Server Messages 12 | CLIENT_SET_PIXEL_FORMAT = 0 13 | CLIENT_SET_ENCODINGS = 2 14 | CLIENT_FRAMEBUFFER_UPDATE_REQUEST = 3 15 | CLIENT_KEY_EVENT = 4 16 | CLIENT_POINTER_EVENT = 5 17 | CLIENT_CUT_TEXT = 6 18 | 19 | # Server to Client Messages 20 | SERVER_FRAMEBUFFER_UPDATE = 0 21 | SERVER_SET_COLOUR_MAP_ENTRIES = 1 22 | SERVER_BELL = 2 23 | SERVER_CUT_TEXT = 3 24 | 25 | 26 | class RFB(dpkt.Packet): 27 | """Remote Framebuffer Protocol. 28 | 29 | TODO: Longer class information.... 30 | 31 | Attributes: 32 | __hdr__: Header fields of RADIUS. 33 | TODO. 34 | """ 35 | 36 | __hdr__ = ( 37 | ('type', 'B', 0), 38 | ) 39 | 40 | 41 | class SetPixelFormat(dpkt.Packet): 42 | __hdr__ = ( 43 | ('pad', '3s', b''), 44 | ('pixel_fmt', '16s', b'') 45 | ) 46 | 47 | 48 | class SetEncodings(dpkt.Packet): 49 | __hdr__ = ( 50 | ('pad', '1s', b''), 51 | ('num_encodings', 'H', 0) 52 | ) 53 | 54 | 55 | class FramebufferUpdateRequest(dpkt.Packet): 56 | __hdr__ = ( 57 | ('incremental', 'B', 0), 58 | ('x_position', 'H', 0), 59 | ('y_position', 'H', 0), 60 | ('width', 'H', 0), 61 | ('height', 'H', 0) 62 | ) 63 | 64 | 65 | class KeyEvent(dpkt.Packet): 66 | __hdr__ = ( 67 | ('down_flag', 'B', 0), 68 | ('pad', '2s', b''), 69 | ('key', 'I', 0) 70 | ) 71 | 72 | 73 | class PointerEvent(dpkt.Packet): 74 | __hdr__ = ( 75 | ('button_mask', 'B', 0), 76 | ('x_position', 'H', 0), 77 | ('y_position', 'H', 0) 78 | ) 79 | 80 | 81 | class FramebufferUpdate(dpkt.Packet): 82 | __hdr__ = ( 83 | ('pad', '1s', b''), 84 | ('num_rects', 'H', 0) 85 | ) 86 | 87 | 88 | class SetColourMapEntries(dpkt.Packet): 89 | __hdr__ = ( 90 | ('pad', '1s', b''), 91 | ('first_colour', 'H', 0), 92 | ('num_colours', 'H', 0) 93 | ) 94 | 95 | 96 | class CutText(dpkt.Packet): 97 | __hdr__ = ( 98 | ('pad', '3s', b''), 99 | ('length', 'I', 0) 100 | ) 101 | -------------------------------------------------------------------------------- /dpkt/rip.py: -------------------------------------------------------------------------------- 1 | # $Id: rip.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Routing Information Protocol.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | 9 | # RIP v2 - RFC 2453 10 | # http://tools.ietf.org/html/rfc2453 11 | 12 | REQUEST = 1 13 | RESPONSE = 2 14 | 15 | 16 | class RIP(dpkt.Packet): 17 | """Routing Information Protocol. 18 | 19 | TODO: Longer class information.... 20 | 21 | Attributes: 22 | __hdr__: Header fields of RIP. 23 | TODO. 24 | """ 25 | 26 | __hdr__ = ( 27 | ('cmd', 'B', REQUEST), 28 | ('v', 'B', 2), 29 | ('rsvd', 'H', 0) 30 | ) 31 | 32 | def unpack(self, buf): 33 | dpkt.Packet.unpack(self, buf) 34 | l_ = [] 35 | self.auth = None 36 | while self.data: 37 | rte = RTE(self.data[:20]) 38 | if rte.family == 0xFFFF: 39 | self.auth = Auth(self.data[:20]) 40 | else: 41 | l_.append(rte) 42 | self.data = self.data[20:] 43 | self.data = self.rtes = l_ 44 | 45 | def __len__(self): 46 | n = self.__hdr_len__ 47 | if self.auth: 48 | n += len(self.auth) 49 | n += sum(map(len, self.rtes)) 50 | return n 51 | 52 | def __bytes__(self): 53 | auth = b'' 54 | if self.auth: 55 | auth = bytes(self.auth) 56 | return self.pack_hdr() + auth + b''.join(map(bytes, self.rtes)) 57 | 58 | 59 | class RTE(dpkt.Packet): 60 | __hdr__ = ( 61 | ('family', 'H', 2), 62 | ('route_tag', 'H', 0), 63 | ('addr', 'I', 0), 64 | ('subnet', 'I', 0), 65 | ('next_hop', 'I', 0), 66 | ('metric', 'I', 1) 67 | ) 68 | 69 | 70 | class Auth(dpkt.Packet): 71 | __hdr__ = ( 72 | ('rsvd', 'H', 0xFFFF), 73 | ('type', 'H', 2), 74 | ('auth', '16s', 0) 75 | ) 76 | 77 | 78 | def test_creation_with_auth(): 79 | from binascii import unhexlify 80 | 81 | buf_auth = unhexlify( 82 | 'ffff' # rsvd 83 | '0002' # type 84 | '0123456789abcdef' # auth 85 | '0123456789abcdef' # auth 86 | ) 87 | auth_direct = Auth(buf_auth) 88 | assert bytes(auth_direct) == buf_auth 89 | 90 | buf_rte = unhexlify( 91 | '0002' # family 92 | '0000' # route_tag 93 | '01020300' # addr 94 | 'ffffff00' # subnet 95 | '00000000' # next_hop 96 | '00000001' # metric 97 | ) 98 | 99 | rte = RTE(buf_rte) 100 | assert bytes(rte) == buf_rte 101 | 102 | buf_rip = unhexlify( 103 | '02' # cmd 104 | '02' # v 105 | '0000' # rsvd 106 | ) 107 | rip = RIP(buf_rip + buf_auth + buf_rte) 108 | 109 | assert rip.auth 110 | assert rip.auth.rsvd == 0xffff 111 | assert rip.auth.type == 2 112 | assert rip.auth.auth == unhexlify('0123456789abcdef') * 2 113 | 114 | assert len(rip.rtes) == 1 115 | 116 | rte = rip.rtes[0] 117 | assert rte.family == 2 118 | assert rte.route_tag == 0 119 | assert rte.metric == 1 120 | 121 | assert bytes(rip) == buf_rip + buf_auth + buf_rte 122 | assert len(rip) == len(buf_rip + buf_auth + buf_rte) 123 | -------------------------------------------------------------------------------- /dpkt/rtp.py: -------------------------------------------------------------------------------- 1 | # $Id: rtp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Real-Time Transport Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from .dpkt import Packet 7 | 8 | # version 1100 0000 0000 0000 ! 0xC000 14 9 | # p 0010 0000 0000 0000 ! 0x2000 13 10 | # x 0001 0000 0000 0000 ! 0x1000 12 11 | # cc 0000 1111 0000 0000 ! 0x0F00 8 12 | # m 0000 0000 1000 0000 ! 0x0080 7 13 | # pt 0000 0000 0111 1111 ! 0x007F 0 14 | # 15 | 16 | _VERSION_MASK = 0xC000 17 | _P_MASK = 0x2000 18 | _X_MASK = 0x1000 19 | _CC_MASK = 0x0F00 20 | _M_MASK = 0x0080 21 | _PT_MASK = 0x007F 22 | _VERSION_SHIFT = 14 23 | _P_SHIFT = 13 24 | _X_SHIFT = 12 25 | _CC_SHIFT = 8 26 | _M_SHIFT = 7 27 | _PT_SHIFT = 0 28 | 29 | VERSION = 2 30 | 31 | 32 | class RTP(Packet): 33 | """Real-Time Transport Protocol. 34 | 35 | TODO: Longer class information.... 36 | 37 | Attributes: 38 | __hdr__: Header fields of RTP. 39 | TODO. 40 | """ 41 | 42 | __hdr__ = ( 43 | ('_type', 'H', 0x8000), 44 | ('seq', 'H', 0), 45 | ('ts', 'I', 0), 46 | ('ssrc', 'I', 0), 47 | ) 48 | csrc = b'' 49 | 50 | @property 51 | def version(self): 52 | return (self._type & _VERSION_MASK) >> _VERSION_SHIFT 53 | 54 | @version.setter 55 | def version(self, ver): 56 | self._type = (ver << _VERSION_SHIFT) | (self._type & ~_VERSION_MASK) 57 | 58 | @property 59 | def p(self): 60 | return (self._type & _P_MASK) >> _P_SHIFT 61 | 62 | @p.setter 63 | def p(self, p): 64 | self._type = (p << _P_SHIFT) | (self._type & ~_P_MASK) 65 | 66 | @property 67 | def x(self): 68 | return (self._type & _X_MASK) >> _X_SHIFT 69 | 70 | @x.setter 71 | def x(self, x): 72 | self._type = (x << _X_SHIFT) | (self._type & ~_X_MASK) 73 | 74 | @property 75 | def cc(self): 76 | return (self._type & _CC_MASK) >> _CC_SHIFT 77 | 78 | @cc.setter 79 | def cc(self, cc): 80 | self._type = (cc << _CC_SHIFT) | (self._type & ~_CC_MASK) 81 | 82 | @property 83 | def m(self): 84 | return (self._type & _M_MASK) >> _M_SHIFT 85 | 86 | @m.setter 87 | def m(self, m): 88 | self._type = (m << _M_SHIFT) | (self._type & ~_M_MASK) 89 | 90 | @property 91 | def pt(self): 92 | return (self._type & _PT_MASK) >> _PT_SHIFT 93 | 94 | @pt.setter 95 | def pt(self, m): 96 | self._type = (m << _PT_SHIFT) | (self._type & ~_PT_MASK) 97 | 98 | def __len__(self): 99 | return self.__hdr_len__ + len(self.csrc) + len(self.data) 100 | 101 | def __bytes__(self): 102 | return self.pack_hdr() + self.csrc + bytes(self.data) 103 | 104 | def unpack(self, buf): 105 | super(RTP, self).unpack(buf) 106 | self.csrc = buf[self.__hdr_len__:self.__hdr_len__ + self.cc * 4] 107 | self.data = buf[self.__hdr_len__ + self.cc * 4:] 108 | 109 | 110 | def test_rtp(): 111 | rtp = RTP( 112 | b'\x80\x08\x4d\x01\x00\x01\x00\xe0\x34\x3f\xfa\x34\x53\x53\x53\x56\x53\x5d\x56\x57\xd5\xd6' 113 | b'\xd1\xde\xdf\xd3\xd9\xda\xdf\xdc\xdf\xd8\xdd\xd4\xdd\xd9\xd1\xd6\xdc\xda\xde\xdd\xc7\xc1' 114 | b'\xdf\xdf\xda\xdb\xdd\xdd\xc4\xd9\x55\x57\xd4\x50\x44\x44\x5b\x44\x4f\x4c\x47\x40\x4c\x47' 115 | b'\x59\x5b\x58\x5d\x56\x56\x53\x56\xd5\xd5\x54\x55\xd6\xd6\xd4\xd1\xd1\xd0\xd1\xd5\xdd\xd6' 116 | b'\x55\xd4\xd6\xd1\xd4\xd6\xd7\xd7\xd5\xd4\xd0\xd7\xd1\xd4\xd2\xdc\xd6\xdc\xdf\xdc\xdd\xd2' 117 | b'\xde\xdc\xd0\xdd\xdc\xd0\xd6\xd6\xd6\x55\x54\x55\x57\x57\x56\x50\x50\x5c\x5c\x52\x5d\x5d' 118 | b'\x5f\x5e\x5d\x5e\x52\x50\x52\x56\x54\x57\x55\x55\xd4\xd7\x55\xd5\x55\x55\x55\x55\x55\x54' 119 | b'\x57\x54\x55\x55\xd5\xd5\xd7\xd6\xd7\xd1\xd1\xd3\xd2\xd3\xd2\xd2\xd3\xd3' 120 | ) 121 | assert (rtp.version == 2) 122 | assert (rtp.p == 0) 123 | assert (rtp.x == 0) 124 | assert (rtp.cc == 0) 125 | assert (rtp.m == 0) 126 | assert (rtp.pt == 8) 127 | assert (rtp.seq == 19713) 128 | assert (rtp.ts == 65760) 129 | assert (rtp.ssrc == 0x343ffa34) 130 | assert (len(rtp) == 172) 131 | assert (bytes(rtp) == ( 132 | b'\x80\x08\x4d\x01\x00\x01\x00\xe0\x34\x3f\xfa\x34\x53\x53\x53\x56\x53\x5d\x56\x57\xd5\xd6' 133 | b'\xd1\xde\xdf\xd3\xd9\xda\xdf\xdc\xdf\xd8\xdd\xd4\xdd\xd9\xd1\xd6\xdc\xda\xde\xdd\xc7\xc1' 134 | b'\xdf\xdf\xda\xdb\xdd\xdd\xc4\xd9\x55\x57\xd4\x50\x44\x44\x5b\x44\x4f\x4c\x47\x40\x4c\x47' 135 | b'\x59\x5b\x58\x5d\x56\x56\x53\x56\xd5\xd5\x54\x55\xd6\xd6\xd4\xd1\xd1\xd0\xd1\xd5\xdd\xd6' 136 | b'\x55\xd4\xd6\xd1\xd4\xd6\xd7\xd7\xd5\xd4\xd0\xd7\xd1\xd4\xd2\xdc\xd6\xdc\xdf\xdc\xdd\xd2' 137 | b'\xde\xdc\xd0\xdd\xdc\xd0\xd6\xd6\xd6\x55\x54\x55\x57\x57\x56\x50\x50\x5c\x5c\x52\x5d\x5d' 138 | b'\x5f\x5e\x5d\x5e\x52\x50\x52\x56\x54\x57\x55\x55\xd4\xd7\x55\xd5\x55\x55\x55\x55\x55\x54' 139 | b'\x57\x54\x55\x55\xd5\xd5\xd7\xd6\xd7\xd1\xd1\xd3\xd2\xd3\xd2\xd2\xd3\xd3' 140 | )) 141 | 142 | # the following tests RTP header setters 143 | rtp = RTP() 144 | rtp.m = 1 145 | rtp.pt = 3 146 | rtp.seq = 1234 147 | rtp.ts = 5678 148 | rtp.ssrc = 0xabcdef01 149 | assert (rtp.m == 1) 150 | assert (rtp.pt == 3) 151 | assert (rtp.seq == 1234) 152 | assert (rtp.ts == 5678) 153 | assert (rtp.ssrc == 0xabcdef01) 154 | 155 | 156 | def test_rtp_properties(): 157 | from .compat import compat_izip 158 | 159 | rtp = RTP() 160 | properties = ['version', 'p', 'x', 'cc', 'm', 'pt'] 161 | defaults = [2, 0, 0, 0, 0, 0] 162 | for prop, default in compat_izip(properties, defaults): 163 | assert hasattr(rtp, prop) 164 | assert getattr(rtp, prop) == default 165 | setattr(rtp, prop, 1) 166 | assert getattr(rtp, prop) == 1 167 | -------------------------------------------------------------------------------- /dpkt/rx.py: -------------------------------------------------------------------------------- 1 | # $Id: rx.py 23 2006-11-08 15:45:33Z jonojono $ 2 | # -*- coding: utf-8 -*- 3 | """Rx Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | # Types 9 | DATA = 0x01 10 | ACK = 0x02 11 | BUSY = 0x03 12 | ABORT = 0x04 13 | ACKALL = 0x05 14 | CHALLENGE = 0x06 15 | RESPONSE = 0x07 16 | DEBUG = 0x08 17 | 18 | # Flags 19 | CLIENT_INITIATED = 0x01 20 | REQUEST_ACK = 0x02 21 | LAST_PACKET = 0x04 22 | MORE_PACKETS = 0x08 23 | SLOW_START_OK = 0x20 24 | JUMBO_PACKET = 0x20 25 | 26 | # Security 27 | SEC_NONE = 0x00 28 | SEC_BCRYPT = 0x01 29 | SEC_RXKAD = 0x02 30 | SEC_RXKAD_ENC = 0x03 31 | 32 | 33 | class Rx(dpkt.Packet): 34 | """Rx Protocol. 35 | 36 | TODO: Longer class information.... 37 | 38 | Attributes: 39 | __hdr__: Header fields of Rx. 40 | TODO. 41 | """ 42 | 43 | __hdr__ = ( 44 | ('epoch', 'I', 0), 45 | ('cid', 'I', 0), 46 | ('call', 'I', 1), 47 | ('seq', 'I', 0), 48 | ('serial', 'I', 1), 49 | ('type', 'B', 0), 50 | ('flags', 'B', CLIENT_INITIATED), 51 | ('status', 'B', 0), 52 | ('security', 'B', 0), 53 | ('sum', 'H', 0), 54 | ('service', 'H', 0) 55 | ) 56 | -------------------------------------------------------------------------------- /dpkt/sccp.py: -------------------------------------------------------------------------------- 1 | # $Id: sccp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Cisco Skinny Client Control Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | KEYPAD_BUTTON = 0x00000003 9 | OFF_HOOK = 0x00000006 10 | ON_HOOK = 0x00000007 11 | OPEN_RECEIVE_CHANNEL_ACK = 0x00000022 12 | START_TONE = 0x00000082 13 | STOP_TONE = 0x00000083 14 | SET_LAMP = 0x00000086 15 | SET_SPEAKER_MODE = 0x00000088 16 | START_MEDIA_TRANSMIT = 0x0000008A 17 | STOP_MEDIA_TRANSMIT = 0x0000008B 18 | CALL_INFO = 0x0000008F 19 | DEFINE_TIME_DATE = 0x00000094 20 | DISPLAY_TEXT = 0x00000099 21 | OPEN_RECEIVE_CHANNEL = 0x00000105 22 | CLOSE_RECEIVE_CHANNEL = 0x00000106 23 | SELECT_SOFTKEYS = 0x00000110 24 | CALL_STATE = 0x00000111 25 | DISPLAY_PROMPT_STATUS = 0x00000112 26 | CLEAR_PROMPT_STATUS = 0x00000113 27 | ACTIVATE_CALL_PLANE = 0x00000116 28 | 29 | 30 | class ActivateCallPlane(dpkt.Packet): 31 | __byte_order__ = '<' 32 | __hdr__ = ( 33 | ('line_instance', 'I', 0), 34 | ) 35 | 36 | 37 | class CallInfo(dpkt.Packet): 38 | __byte_order__ = '<' 39 | __hdr__ = ( 40 | ('calling_party_name', '40s', b''), 41 | ('calling_party', '24s', b''), 42 | ('called_party_name', '40s', b''), 43 | ('called_party', '24s', b''), 44 | ('line_instance', 'I', 0), 45 | ('call_id', 'I', 0), 46 | ('call_type', 'I', 0), 47 | ('orig_called_party_name', '40s', b''), 48 | ('orig_called_party', '24s', b'') 49 | ) 50 | 51 | 52 | class CallState(dpkt.Packet): 53 | __byte_order__ = '<' 54 | __hdr__ = ( 55 | ('call_state', 'I', 12), # 12: Proceed, 15: Connected 56 | ('line_instance', 'I', 1), 57 | ('call_id', 'I', 0) 58 | ) 59 | 60 | 61 | class ClearPromptStatus(dpkt.Packet): 62 | __byte_order__ = '<' 63 | __hdr__ = ( 64 | ('line_instance', 'I', 1), 65 | ('call_id', 'I', 0) 66 | ) 67 | 68 | 69 | class CloseReceiveChannel(dpkt.Packet): 70 | __byte_order__ = '<' 71 | __hdr__ = ( 72 | ('conference_id', 'I', 0), 73 | ('passthruparty_id', 'I', 0), 74 | ) 75 | 76 | 77 | class DisplayPromptStatus(dpkt.Packet): 78 | __byte_order__ = '<' 79 | __hdr__ = ( 80 | ('msg_timeout', 'I', 0), 81 | ('display_msg', '32s', b''), 82 | ('line_instance', 'I', 1), 83 | ('call_id', 'I', 0) 84 | ) 85 | 86 | 87 | class DisplayText(dpkt.Packet): 88 | __byte_order__ = '<' 89 | __hdr__ = ( 90 | ('display_msg', '36s', b''), 91 | ) 92 | 93 | 94 | class KeypadButton(dpkt.Packet): 95 | __byte_order__ = '<' 96 | __hdr__ = ( 97 | ('button', 'I', 0), 98 | ) 99 | 100 | 101 | class OpenReceiveChannel(dpkt.Packet): 102 | __byte_order__ = '<' 103 | __hdr__ = ( 104 | ('conference_id', 'I', 0), 105 | ('passthruparty_id', 'I', 0), 106 | ('ms_packet', 'I', 0), 107 | ('payload_capability', 'I', 4), # 4: G.711 u-law 64k 108 | ('echo_cancel_type', 'I', 4), 109 | ('g723_bitrate', 'I', 0), 110 | ) 111 | 112 | 113 | class OpenReceiveChannelAck(dpkt.Packet): 114 | __byte_order__ = '<' 115 | __hdr__ = ( 116 | ('channel_status', 'I', 0), 117 | ('ip', '4s', b''), 118 | ('port', 'I', 0), 119 | ('passthruparty_id', 'I', 0), 120 | ) 121 | 122 | 123 | class SelectStartKeys(dpkt.Packet): 124 | __byte_order__ = '<' 125 | __hdr__ = ( 126 | ('line_id', 'I', 1), 127 | ('call_id', 'I', 0), 128 | ('softkey_set', 'I', 8), 129 | ('softkey_map', 'I', 0xffffffff) 130 | ) 131 | 132 | 133 | class SetLamp(dpkt.Packet): 134 | __byte_order__ = '<' 135 | __hdr__ = ( 136 | ('stimulus', 'I', 9), # 9: Line 137 | ('stimulus_instance', 'I', 1), 138 | ('lamp_mode', 'I', 1), 139 | ) 140 | 141 | 142 | class SetSpeakerMode(dpkt.Packet): 143 | __byte_order__ = '<' 144 | __hdr__ = ( 145 | ('speaker', 'I', 2), # 2: SpeakerOff 146 | ) 147 | 148 | 149 | class StartMediaTransmission(dpkt.Packet): 150 | __byte_order__ = '<' 151 | __hdr__ = ( 152 | ('conference_id', 'I', 0), 153 | ('passthruparty_id', 'I', 0), 154 | ('ipv4_or_ipv6', 'I', 0), 155 | ('remote_ip', '16s', b''), 156 | ('remote_port', 'I', 0), 157 | ('ms_packet', 'I', 0), 158 | ('payload_capability', 'I', 4), # 4: G.711 u-law 64k 159 | ('precedence', 'I', 0), 160 | ('silence_suppression', 'I', 0), 161 | ('max_frames_per_pkt', 'I', 1), 162 | ('g723_bitrate', 'I', 0), 163 | ('call_reference', 'I', 0) 164 | ) 165 | 166 | 167 | class StartTone(dpkt.Packet): 168 | __byte_order__ = '<' 169 | __hdr__ = ( 170 | ('tone', 'I', 0x24), # 0x24: AlertingTone 171 | ) 172 | 173 | 174 | class StopMediaTransmission(dpkt.Packet): 175 | __byte_order__ = '<' 176 | __hdr__ = ( 177 | ('conference_id', 'I', 0), 178 | ('passthruparty_id', 'I', 0), 179 | ) 180 | 181 | 182 | class SCCP(dpkt.Packet): 183 | """Cisco Skinny Client Control Protocol. 184 | 185 | TODO: Longer class information.... 186 | 187 | Attributes: 188 | __hdr__: Header fields of SCCP. 189 | TODO. 190 | """ 191 | 192 | __byte_order__ = '<' 193 | __hdr__ = ( 194 | ('len', 'I', 0), 195 | ('rsvd', 'I', 0), 196 | ('msgid', 'I', 0), 197 | ('msg', '0s', b''), 198 | ) 199 | _msgsw = { 200 | KEYPAD_BUTTON: KeypadButton, 201 | OPEN_RECEIVE_CHANNEL_ACK: OpenReceiveChannelAck, 202 | START_TONE: StartTone, 203 | SET_LAMP: SetLamp, 204 | START_MEDIA_TRANSMIT: StartMediaTransmission, 205 | STOP_MEDIA_TRANSMIT: StopMediaTransmission, 206 | CALL_INFO: CallInfo, 207 | DISPLAY_TEXT: DisplayText, 208 | OPEN_RECEIVE_CHANNEL: OpenReceiveChannel, 209 | CLOSE_RECEIVE_CHANNEL: CloseReceiveChannel, 210 | CALL_STATE: CallState, 211 | DISPLAY_PROMPT_STATUS: DisplayPromptStatus, 212 | CLEAR_PROMPT_STATUS: ClearPromptStatus, 213 | ACTIVATE_CALL_PLANE: ActivateCallPlane, 214 | } 215 | 216 | def unpack(self, buf): 217 | dpkt.Packet.unpack(self, buf) 218 | n = self.len - 4 219 | if n > len(self.data): 220 | raise dpkt.NeedData('not enough data') 221 | self.msg, self.data = self.data[:n], self.data[n:] 222 | try: 223 | p = self._msgsw[self.msgid](self.msg) 224 | setattr(self, p.__class__.__name__.lower(), p) 225 | except (KeyError, dpkt.UnpackError): 226 | pass 227 | 228 | 229 | def test_sccp(): 230 | import pytest 231 | from binascii import unhexlify 232 | buf = unhexlify( 233 | '08000000' # len 234 | '00000000' # rsvd 235 | '03000000' # msgid (KEYPAD_BUTTON) 236 | 237 | 'abcdef01' # msg 238 | '23456789' # daat 239 | ) 240 | sccp = SCCP(buf) 241 | assert sccp.msg == b'\xab\xcd\xef\x01' 242 | assert sccp.data == b'\x23\x45\x67\x89' 243 | assert isinstance(sccp.keypadbutton, KeypadButton) 244 | 245 | # len is too long for data, raises NeedData 246 | buf = unhexlify( 247 | '88880000' # len 248 | '00000000' # rsvd 249 | '00000003' # msgid (KEYPAD_BUTTON) 250 | 251 | 'abcdef01' # msg 252 | ) 253 | with pytest.raises(dpkt.NeedData): 254 | SCCP(buf) 255 | 256 | # msgid is invalid, raises KeyError on _msgsw (silently caught) 257 | buf = unhexlify( 258 | '08000000' # len 259 | '00000000' # rsvd 260 | '00000003' # msgid (invalid) 261 | 262 | 'abcdef01' # msg 263 | ) 264 | sccp = SCCP(buf) 265 | assert sccp.msg == b'\xab\xcd\xef\x01' 266 | assert sccp.data == b'' 267 | -------------------------------------------------------------------------------- /dpkt/sctp.py: -------------------------------------------------------------------------------- 1 | # $Id: sctp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Stream Control Transmission Protocol.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | from . import crc32c 9 | 10 | # Stream Control Transmission Protocol 11 | # http://tools.ietf.org/html/rfc2960 12 | 13 | # Chunk Types 14 | DATA = 0 15 | INIT = 1 16 | INIT_ACK = 2 17 | SACK = 3 18 | HEARTBEAT = 4 19 | HEARTBEAT_ACK = 5 20 | ABORT = 6 21 | SHUTDOWN = 7 22 | SHUTDOWN_ACK = 8 23 | ERROR = 9 24 | COOKIE_ECHO = 10 25 | COOKIE_ACK = 11 26 | ECNE = 12 27 | CWR = 13 28 | SHUTDOWN_COMPLETE = 14 29 | 30 | 31 | class SCTP(dpkt.Packet): 32 | """Stream Control Transmission Protocol. 33 | 34 | TODO: Longer class information.... 35 | 36 | Attributes: 37 | __hdr__: Header fields of SCTP. 38 | TODO. 39 | """ 40 | 41 | __hdr__ = ( 42 | ('sport', 'H', 0), 43 | ('dport', 'H', 0), 44 | ('vtag', 'I', 0), 45 | ('sum', 'I', 0) 46 | ) 47 | 48 | def unpack(self, buf): 49 | dpkt.Packet.unpack(self, buf) 50 | l_ = [] 51 | while self.data: 52 | chunk = Chunk(self.data) 53 | l_.append(chunk) 54 | if len(chunk) == 0: 55 | self.data = b'' 56 | break 57 | self.data = self.data[len(chunk):] 58 | self.chunks = l_ 59 | 60 | def __len__(self): 61 | return self.__hdr_len__ + sum(len(x) for x in self.chunks) 62 | 63 | def __bytes__(self): 64 | l_ = [bytes(x) for x in self.chunks] 65 | if self.sum == 0: 66 | s = crc32c.add(0xffffffff, self.pack_hdr()) 67 | for x in l_: 68 | s = crc32c.add(s, x) 69 | self.sum = crc32c.done(s) 70 | return self.pack_hdr() + b''.join(l_) 71 | 72 | 73 | class Chunk(dpkt.Packet): 74 | __hdr__ = ( 75 | ('type', 'B', INIT), 76 | ('flags', 'B', 0), 77 | ('len', 'H', 0) 78 | ) 79 | 80 | def unpack(self, buf): 81 | dpkt.Packet.unpack(self, buf) 82 | 83 | self.data = self.data[:self.len - self.__hdr_len__] 84 | self.padding = b'' # optional padding for DATA chunks 85 | 86 | # SCTP DATA Chunked is padded, 4-bytes aligned 87 | if self.type == DATA and self.len % 4: 88 | plen = 4 - self.len % 4 # padded length 89 | if plen: 90 | pos = self.__hdr_len__ + len(self.data) # end of data in buf 91 | self.padding = buf[pos:pos + plen] 92 | 93 | def __len__(self): 94 | return self.len + len(self.padding) 95 | 96 | def __bytes__(self): 97 | return self.pack_hdr() + bytes(self.data) + self.padding 98 | 99 | 100 | __s = (b'\x80\x44\x00\x50\x00\x00\x00\x00\x30\xba\xef\x54\x01\x00\x00\x3c\x3b\xb9\x9c\x46\x00\x01' 101 | b'\xa0\x00\x00\x0a\xff\xff\x2b\x2d\x7e\xb2\x00\x05\x00\x08\x9b\xe6\x18\x9b\x00\x05\x00\x08' 102 | b'\x9b\xe6\x18\x9c\x00\x0c\x00\x06\x00\x05\x00\x00\x80\x00\x00\x04\xc0\x00\x00\x04\xc0\x06' 103 | b'\x00\x08\x00\x00\x00\x00') 104 | 105 | 106 | def test_sctp_pack(): 107 | sctp = SCTP(__s) 108 | assert (__s == bytes(sctp)) 109 | sctp.sum = 0 110 | assert (__s == bytes(sctp)) 111 | 112 | 113 | def test_sctp_unpack(): 114 | sctp = SCTP(__s) 115 | assert (sctp.sport == 32836) 116 | assert (sctp.dport == 80) 117 | assert (len(sctp.chunks) == 1) 118 | assert (len(sctp) == 72) 119 | chunk = sctp.chunks[0] 120 | assert (chunk.type == INIT) 121 | assert (chunk.len == 60) 122 | 123 | 124 | def test_sctp_data_chunk(): # https://github.com/kbandla/dpkt/issues/499 125 | # packet 5 from 'sctp-www.cap' downloaded from https://wiki.wireshark.org/SampleCaptures 126 | # chunk len == 419 so requires padding to a 4-byte boundary 127 | d = (b'\x80\x44\x00\x50\xd2\x6a\xc1\xe5\x70\xe5\x5b\x4c\x00\x03\x01\xa3\x2b\x2d\x7e\xb2\x00\x00' 128 | b'\x00\x00\x00\x00\x00\x00\x47\x45\x54\x20\x2f\x20\x48\x54\x54\x50\x2f\x31\x2e\x31\x0d\x0a' 129 | b'\x48\x6f\x73\x74\x3a\x20\x32\x30\x33\x2e\x32\x35\x35\x2e\x32\x35\x32\x2e\x31\x39\x34\x0d' 130 | b'\x0a\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35' 131 | b'\x2e\x30\x20\x28\x58\x31\x31\x3b\x20\x55\x3b\x20\x4c\x69\x6e\x75\x78\x20\x69\x36\x38\x36' 132 | b'\x3b\x20\x6b\x6f\x2d\x4b\x52\x3b\x20\x72\x76\x3a\x31\x2e\x37\x2e\x31\x32\x29\x20\x47\x65' 133 | b'\x63\x6b\x6f\x2f\x32\x30\x30\x35\x31\x30\x30\x37\x20\x44\x65\x62\x69\x61\x6e\x2f\x31\x2e' 134 | b'\x37\x2e\x31\x32\x2d\x31\x0d\x0a\x41\x63\x63\x65\x70\x74\x3a\x20\x74\x65\x78\x74\x2f\x78' 135 | b'\x6d\x6c\x2c\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x6d\x6c\x2c\x61\x70\x70' 136 | b'\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b\x78\x6d\x6c\x2c\x74\x65\x78' 137 | b'\x74\x2f\x68\x74\x6d\x6c\x3b\x71\x3d\x30\x2e\x39\x2c\x74\x65\x78\x74\x2f\x70\x6c\x61\x69' 138 | b'\x6e\x3b\x71\x3d\x30\x2e\x38\x2c\x69\x6d\x61\x67\x65\x2f\x70\x6e\x67\x2c\x2a\x2f\x2a\x3b' 139 | b'\x71\x3d\x30\x2e\x35\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x4c\x61\x6e\x67\x75\x61\x67\x65' 140 | b'\x3a\x20\x6b\x6f\x2c\x65\x6e\x2d\x75\x73\x3b\x71\x3d\x30\x2e\x37\x2c\x65\x6e\x3b\x71\x3d' 141 | b'\x30\x2e\x33\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x45\x6e\x63\x6f\x64\x69\x6e\x67\x3a\x20' 142 | b'\x67\x7a\x69\x70\x2c\x64\x65\x66\x6c\x61\x74\x65\x0d\x0a\x41\x63\x63\x65\x70\x74\x2d\x43' 143 | b'\x68\x61\x72\x73\x65\x74\x3a\x20\x45\x55\x43\x2d\x4b\x52\x2c\x75\x74\x66\x2d\x38\x3b\x71' 144 | b'\x3d\x30\x2e\x37\x2c\x2a\x3b\x71\x3d\x30\x2e\x37\x0d\x0a\x4b\x65\x65\x70\x2d\x41\x6c\x69' 145 | b'\x76\x65\x3a\x20\x33\x30\x30\x0d\x0a\x43\x6f\x6e\x6e\x65\x63\x74\x69\x6f\x6e\x3a\x20\x6b' 146 | b'\x65\x65\x70\x2d\x61\x6c\x69\x76\x65\x0d\x0a\x0d\x0a\x00') # <-- ends with \x00 padding 147 | 148 | sctp = SCTP(d) 149 | assert sctp.chunks 150 | assert len(sctp.chunks) == 1 151 | 152 | ch = sctp.chunks[0] 153 | assert ch.type == DATA 154 | assert ch.len == 419 155 | assert len(ch) == 420 # 419 +1 byte padding 156 | assert ch.data[-14:] == b'keep-alive\r\n\r\n' # no padding byte at the end 157 | 158 | # no remaining sctp data 159 | assert sctp.data == b'' 160 | 161 | # test packing of the padded chunk 162 | assert bytes(ch) == d[SCTP.__hdr_len__:] 163 | 164 | 165 | 166 | def test_malformed_sctp_data_chunk(): 167 | # packet 7964 from '4.pcap' downloaded from https://research.unsw.edu.au/projects/unsw-nb15-dataset 168 | d = (b'\x27\x0f\xe1\xc3\xc2\x73\x4d\x32\x4f\x54\x27\x8c' #header 169 | b'\x0b\x00\x00\x04' #chunk 0, COOKIE_ACK chunk 170 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') #chunk 1, malformed DATA chunk, size labeled as 0 171 | 172 | 173 | sctp = SCTP(d) 174 | assert sctp.chunks 175 | assert len(sctp.chunks) == 2 176 | 177 | ch = sctp.chunks[1] 178 | assert ch.type == DATA 179 | assert ch.len == 0 180 | assert len(ch) == 0 181 | assert ch.data == b'\x00\x00' 182 | 183 | # no remaining sctp data 184 | assert sctp.data == b'' 185 | -------------------------------------------------------------------------------- /dpkt/sip.py: -------------------------------------------------------------------------------- 1 | # $Id: sip.py 48 2008-05-27 17:31:15Z yardley $ 2 | # -*- coding: utf-8 -*- 3 | """Session Initiation Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import http 7 | 8 | 9 | class Request(http.Request): 10 | """SIP request. 11 | 12 | TODO: Longer class information.... 13 | 14 | Attributes: 15 | __hdr__: Header fields of SIP request. 16 | TODO. 17 | """ 18 | 19 | __hdr_defaults__ = { 20 | 'method': 'INVITE', 21 | 'uri': 'sip:user@example.com', 22 | 'version': '2.0', 23 | 'headers': {'To': '', 'From': '', 'Call-ID': '', 'CSeq': '', 'Contact': ''} 24 | } 25 | __methods = dict.fromkeys(( 26 | 'ACK', 'BYE', 'CANCEL', 'INFO', 'INVITE', 'MESSAGE', 'NOTIFY', 27 | 'OPTIONS', 'PRACK', 'PUBLISH', 'REFER', 'REGISTER', 'SUBSCRIBE', 28 | 'UPDATE' 29 | )) 30 | __proto = 'SIP' 31 | 32 | 33 | class Response(http.Response): 34 | """SIP response. 35 | 36 | TODO: Longer class information.... 37 | 38 | Attributes: 39 | __hdr__: Header fields of SIP response. 40 | TODO. 41 | """ 42 | 43 | __hdr_defaults__ = { 44 | 'version': '2.0', 45 | 'status': '200', 46 | 'reason': 'OK', 47 | 'headers': {'To': '', 'From': '', 'Call-ID': '', 'CSeq': '', 'Contact': ''} 48 | } 49 | __proto = 'SIP' 50 | -------------------------------------------------------------------------------- /dpkt/sll.py: -------------------------------------------------------------------------------- 1 | # $Id: sll.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Linux libpcap "cooked" capture encapsulation.""" 4 | from __future__ import absolute_import 5 | 6 | from . import arp 7 | from . import dpkt 8 | from . import ethernet 9 | 10 | 11 | class SLL(dpkt.Packet): 12 | """Linux libpcap "cooked" capture encapsulation. 13 | 14 | TODO: Longer class information.... 15 | 16 | Attributes: 17 | __hdr__: Header fields of SLL. 18 | TODO. 19 | """ 20 | 21 | __hdr__ = ( 22 | ('type', 'H', 0), # 0: to us, 1: bcast, 2: mcast, 3: other, 4: from us 23 | ('hrd', 'H', arp.ARP_HRD_ETH), 24 | ('hlen', 'H', 6), # hardware address length 25 | ('hdr', '8s', b''), # first 8 bytes of link-layer header 26 | ('ethtype', 'H', ethernet.ETH_TYPE_IP), 27 | ) 28 | _typesw = ethernet.Ethernet._typesw 29 | 30 | def unpack(self, buf): 31 | dpkt.Packet.unpack(self, buf) 32 | try: 33 | self.data = self._typesw[self.ethtype](self.data) 34 | setattr(self, self.data.__class__.__name__.lower(), self.data) 35 | except (KeyError, dpkt.UnpackError): 36 | pass 37 | 38 | 39 | def test_sll(): 40 | slldata = (b'\x00\x00\x00\x01\x00\x06\x00\x0b\xdb\x52\x0e\x08\xf6\x7f\x08\x00\x45\x00\x00\x34' 41 | b'\xcc\x6c\x40\x00\x40\x06\x74\x08\x82\xd9\xfa\x8e\x82\xd9\xfa\x0d') 42 | slltest = SLL(slldata) 43 | assert slltest.type == 0 44 | assert slltest.hrd == 1 45 | assert slltest.hlen == 6 46 | assert slltest.hdr == b'\x00\x0b\xdb\x52\x0e\x08\xf6\x7f' 47 | assert slltest.ethtype == 0x0800 48 | 49 | # give invalid ethtype of 0x1234 to make sure error is caught 50 | slldata2 = (b'\x00\x00\x00\x01\x00\x06\x00\x0b\xdb\x52\x0e\x08\xf6\x7f\x12\x34\x45\x00\x00\x34' 51 | b'\xcc\x6c\x40\x00\x40\x06\x74\x08\x82\xd9\xfa\x8e\x82\xd9\xfa\x0d') 52 | slltest = SLL(slldata2) 53 | -------------------------------------------------------------------------------- /dpkt/sll2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Linux libpcap "cooked v2" capture encapsulation.""" 3 | from __future__ import absolute_import 4 | 5 | from . import arp 6 | from . import dpkt 7 | from . import ethernet 8 | 9 | 10 | class SLL2(dpkt.Packet): 11 | """Linux libpcap "cooked v2" capture encapsulation. 12 | 13 | See https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html 14 | 15 | Attributes: 16 | __hdr__: Header fields of SLLv2. 17 | """ 18 | 19 | __hdr__ = ( 20 | ('ethtype', 'H', ethernet.ETH_TYPE_IP), 21 | ('mbz', 'H', 0), # reserved 22 | ('intindex', 'i', 0), # the 1-based index of the interface on which the packet was observed 23 | ('hrd', 'H', arp.ARP_HRD_ETH), 24 | ('type', 'B', 0), # 0: to us, 1: bcast, 2: mcast, 3: other, 4: from us 25 | ('hlen', 'B', 6), # hardware address length 26 | ('hdr', '8s', b''), # first 8 bytes of link-layer header 27 | ) 28 | _typesw = ethernet.Ethernet._typesw 29 | 30 | def unpack(self, buf): 31 | dpkt.Packet.unpack(self, buf) 32 | try: 33 | self.data = self._typesw[self.ethtype](self.data) 34 | setattr(self, self.data.__class__.__name__.lower(), self.data) 35 | except (KeyError, dpkt.UnpackError): 36 | pass 37 | 38 | 39 | def test_sll2(): 40 | sll2data = (b'\x08\x00\x00\x00\x00\x00\x00\x03\x00\x01\x00\x06\x00\x0b\xdb\x52\x0e\x08\xf6\x7f' 41 | b'\x45\x00\x00\x34\xcc\x6c\x40\x00\x40\x06\x74\x08\x82\xd9\xfa\x8e\x82\xd9\xfa\x0d') 42 | sll2test = SLL2(sll2data) 43 | assert sll2test.type == 0 44 | assert sll2test.mbz == 0 45 | assert sll2test.intindex == 3 46 | assert sll2test.hrd == 1 47 | assert sll2test.hlen == 6 48 | assert sll2test.hdr == b'\x00\x0b\xdb\x52\x0e\x08\xf6\x7f' 49 | assert sll2test.ethtype == 0x0800 50 | 51 | # give invalid ethtype of 0x1234 to make sure error is handled 52 | sll2data2 = (b'\x12\x34\x00\x00\x00\x00\x00\x03\x00\x01\x00\x06\x00\x0b\xdb\x52\x0e\x08\xf6\x7f' 53 | b'\x45\x00\x00\x34\xcc\x6c\x40\x00\x40\x06\x74\x08\x82\xd9\xfa\x8e\x82\xd9\xfa\x0d') 54 | sll2test2 = SLL2(sll2data2) 55 | -------------------------------------------------------------------------------- /dpkt/smb.py: -------------------------------------------------------------------------------- 1 | # $Id: smb.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Server Message Block.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | 9 | 10 | # https://msdn.microsoft.com/en-us/library/ee441774.aspx 11 | 12 | SMB_FLAGS_LOCK_AND_READ_OK = 0x01 13 | SMB_FLAGS_BUF_AVAIL = 0x02 14 | SMB_FLAGS_CASE_INSENSITIVE = 0x08 15 | SMB_FLAGS_CANONICALIZED_PATHS = 0x10 16 | SMB_FLAGS_OPLOCK = 0x20 17 | SMB_FLAGS_OPBATCH = 0x40 18 | SMB_FLAGS_REPLY = 0x80 19 | 20 | SMB_FLAGS2_LONG_NAMES = 0x0001 21 | SMB_FLAGS2_EXTENDED_ATTRIBUTES = 0x0002 22 | SMB_FLAGS2_SECURITY_SIGNATURES = 0x0004 23 | SMB_FLAGS2_COMPRESSED = 0x0008 24 | SMB_FLAGS2_SECURITY_SIGNATURES_REQUIRED = 0x0010 25 | SMB_FLAGS2_IS_LONG_NAME = 0x0040 26 | SMB_FLAGS2_REVERSE_PATH = 0x0400 27 | SMB_FLAGS2_EXTENDED_SECURITY = 0x0800 28 | SMB_FLAGS2_DFS = 0x1000 29 | SMB_FLAGS2_PAGING_IO = 0x2000 30 | SMB_FLAGS2_NT_STATUS = 0x4000 31 | SMB_FLAGS2_UNICODE = 0x8000 32 | 33 | SMB_STATUS_SUCCESS = 0x00000000 34 | 35 | 36 | class SMB(dpkt.Packet): 37 | r"""Server Message Block. 38 | 39 | Server Message Block (SMB) is a communication protocol[1] that Microsoft created for providing 40 | shared access to files and printers across nodes on a network. It also provides an authenticated 41 | inter-process communication (IPC) mechanism. 42 | 43 | Attributes: 44 | __hdr__: SMB Headers 45 | proto: (bytes): Protocol. This field MUST contain the 4-byte literal string '\xFF', 'S', 'M', 'B' (4 bytes) 46 | cmd: (int): Command. Defines SMB command. (1 byte) 47 | status: (int): Status. Communicates error messages from the server to the client. (4 bytes) 48 | flags: (int): Flags. Describes various features in effect for the message.(1 byte) 49 | flags2: (int): Flags2. Represent various features in effect for the message. 50 | Unspecified bits are reserved and MUST be zero. (2 bytes) 51 | _pidhi: (int): PIDHigh. Represents the high-order bytes of a process identifier (PID) (2 bytes) 52 | security: (bytes): SecurityFeatures. Has three possible interpretations. (8 bytes) 53 | rsvd: (int): Reserved. This field is reserved and SHOULD be set to 0x0000. (2 bytes) 54 | tid: (int): TID. A tree identifier (TID). (2 bytes) 55 | _pidlo: (int): PIDLow. The lower 16-bits of the PID. (2 bytes) 56 | uid: (int): UID. A user identifier (UID). (2 bytes) 57 | mid: (int): MID. A multiplex identifier (MID).(2 bytes) 58 | """ 59 | 60 | __byte_order__ = '<' 61 | __hdr__ = [ 62 | ('proto', '4s', b'\xffSMB'), 63 | ('cmd', 'B', 0), 64 | ('status', 'I', SMB_STATUS_SUCCESS), 65 | ('flags', 'B', 0), 66 | ('flags2', 'H', 0), 67 | ('_pidhi', 'H', 0), 68 | ('security', '8s', b''), 69 | ('rsvd', 'H', 0), 70 | ('tid', 'H', 0), 71 | ('_pidlo', 'H', 0), 72 | ('uid', 'H', 0), 73 | ('mid', 'H', 0) 74 | ] 75 | 76 | @property 77 | def pid(self): 78 | return (self._pidhi << 16) | self._pidlo 79 | 80 | @pid.setter 81 | def pid(self, v): 82 | self._pidhi = v >> 16 83 | self._pidlo = v & 0xffff 84 | 85 | 86 | def test_smb(): 87 | buf = (b'\xffSMB\xa0\x00\x00\x00\x00\x08\x03\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 88 | b'\x00\x00\x08\xfa\x7a\x00\x08\x53\x02') 89 | smb = SMB(buf) 90 | 91 | assert smb.flags == SMB_FLAGS_CASE_INSENSITIVE 92 | assert smb.flags2 == (SMB_FLAGS2_UNICODE | SMB_FLAGS2_NT_STATUS | 93 | SMB_FLAGS2_EXTENDED_SECURITY | SMB_FLAGS2_EXTENDED_ATTRIBUTES | SMB_FLAGS2_LONG_NAMES) 94 | assert smb.pid == 31482 95 | assert smb.uid == 2048 96 | assert smb.mid == 595 97 | print(repr(smb)) 98 | 99 | smb = SMB() 100 | smb.pid = 0x00081020 101 | smb.uid = 0x800 102 | assert str(smb) == str(b'\xffSMB\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00' 103 | b'\x00\x00\x00\x00\x00\x00\x00\x20\x10\x00\x08\x00\x00') 104 | -------------------------------------------------------------------------------- /dpkt/stp.py: -------------------------------------------------------------------------------- 1 | # $Id: stp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Spanning Tree Protocol.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | 9 | 10 | class STP(dpkt.Packet): 11 | """Spanning Tree Protocol. 12 | 13 | TODO: Longer class information.... 14 | 15 | Attributes: 16 | __hdr__: Header fields of STP. 17 | TODO. 18 | """ 19 | 20 | __hdr__ = ( 21 | ('proto_id', 'H', 0), 22 | ('v', 'B', 0), 23 | ('type', 'B', 0), 24 | ('flags', 'B', 0), 25 | ('root_id', '8s', b''), 26 | ('root_path', 'I', 0), 27 | ('bridge_id', '8s', b''), 28 | ('port_id', 'H', 0), 29 | ('_age', 'H', 0), 30 | ('_max_age', 'H', 0), 31 | ('_hello', 'H', 0), 32 | ('_fd', 'H', 0) 33 | ) 34 | 35 | @property 36 | def age(self): 37 | return self._age >> 8 38 | 39 | @age.setter 40 | def age(self, age): 41 | self._age = age << 8 42 | 43 | @property 44 | def max_age(self): 45 | return self._max_age >> 8 46 | 47 | @max_age.setter 48 | def max_age(self, max_age): 49 | self._max_age = max_age << 8 50 | 51 | @property 52 | def hello(self): 53 | return self._hello >> 8 54 | 55 | @hello.setter 56 | def hello(self, hello): 57 | self._hello = hello << 8 58 | 59 | @property 60 | def fd(self): 61 | return self._fd >> 8 62 | 63 | @fd.setter 64 | def fd(self, fd): 65 | self._fd = fd << 8 66 | 67 | 68 | def test_stp(): 69 | buf = (b'\x00\x00\x02\x02\x3e\x80\x00\x08\x00\x27\xad\xa3\x41\x00\x00\x00\x00\x80\x00\x08\x00\x27' 70 | b'\xad\xa3\x41\x80\x01\x00\x00\x14\x00\x02\x00\x0f\x00\x00\x00\x00\x00\x02\x00\x14\x00') 71 | stp = STP(buf) 72 | 73 | assert stp.proto_id == 0 74 | assert stp.port_id == 0x8001 75 | assert stp.age == 0 76 | assert stp.max_age == 20 77 | assert stp.hello == 2 78 | assert stp.fd == 15 79 | 80 | assert bytes(stp) == buf 81 | 82 | stp.fd = 100 83 | assert stp.pack_hdr()[-2:] == b'\x64\x00' # 100 << 8 84 | 85 | 86 | def test_properties(): 87 | stp = STP() 88 | stp.age = 10 89 | assert stp.age == 10 90 | 91 | stp.max_age = 20 92 | assert stp.max_age == 20 93 | 94 | stp.hello = 1234 95 | assert stp.hello == 1234 96 | -------------------------------------------------------------------------------- /dpkt/stun.py: -------------------------------------------------------------------------------- 1 | # $Id: stun.py 47 2008-05-27 02:10:00Z jon.oberheide $ 2 | # -*- coding: utf-8 -*- 3 | """Simple Traversal of UDP through NAT.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | import struct 8 | 9 | from . import dpkt 10 | 11 | # STUN - RFC 3489 12 | # http://tools.ietf.org/html/rfc3489 13 | # Each packet has a 20 byte header followed by 0 or more attribute TLVs. 14 | 15 | # Message Types 16 | BINDING_REQUEST = 0x0001 17 | BINDING_RESPONSE = 0x0101 18 | BINDING_ERROR_RESPONSE = 0x0111 19 | SHARED_SECRET_REQUEST = 0x0002 20 | SHARED_SECRET_RESPONSE = 0x0102 21 | SHARED_SECRET_ERROR_RESPONSE = 0x0112 22 | 23 | # Message Attributes 24 | MAPPED_ADDRESS = 0x0001 25 | RESPONSE_ADDRESS = 0x0002 26 | CHANGE_REQUEST = 0x0003 27 | SOURCE_ADDRESS = 0x0004 28 | CHANGED_ADDRESS = 0x0005 29 | USERNAME = 0x0006 30 | PASSWORD = 0x0007 31 | MESSAGE_INTEGRITY = 0x0008 32 | ERROR_CODE = 0x0009 33 | UNKNOWN_ATTRIBUTES = 0x000a 34 | REFLECTED_FROM = 0x000b 35 | 36 | 37 | class STUN(dpkt.Packet): 38 | """Simple Traversal of UDP through NAT. 39 | 40 | STUN - RFC 3489 41 | http://tools.ietf.org/html/rfc3489 42 | Each packet has a 20 byte header followed by 0 or more attribute TLVs. 43 | 44 | Attributes: 45 | __hdr__: Header fields of STUN. 46 | type: (int): STUN Message Type (2 bytes) 47 | len: (int): Message Length (2 bytes) 48 | xid: (bytes): Magic Cookie and Transaction ID (16 bytes) 49 | """ 50 | 51 | __hdr__ = ( 52 | ('type', 'H', 0), 53 | ('len', 'H', 0), 54 | ('xid', '16s', 0) 55 | ) 56 | 57 | 58 | def tlv(buf): 59 | n = 4 60 | t, l_ = struct.unpack('>HH', buf[:n]) 61 | v = buf[n:n + l_] 62 | pad = (n - l_ % n) % n 63 | buf = buf[n + l_ + pad:] 64 | return t, l_, v, buf 65 | 66 | 67 | def parse_attrs(buf): 68 | """Parse STUN.data buffer into a list of (attribute, data) tuples.""" 69 | attrs = [] 70 | while buf: 71 | t, _, v, buf = tlv(buf) 72 | attrs.append((t, v)) 73 | return attrs 74 | 75 | 76 | def test_stun_response(): 77 | s = (b'\x01\x01\x00\x0c\x21\x12\xa4\x42\x53\x4f\x70\x43\x69\x69\x35\x4a\x66\x63\x31\x7a\x00\x01' 78 | b'\x00\x08\x00\x01\x11\x22\x33\x44\x55\x66') 79 | m = STUN(s) 80 | assert m.type == BINDING_RESPONSE 81 | assert m.len == 12 82 | 83 | attrs = parse_attrs(m.data) 84 | assert attrs == [(MAPPED_ADDRESS, b'\x00\x01\x11\x22\x33\x44\x55\x66'), ] 85 | 86 | 87 | def test_stun_padded(): 88 | s = (b'\x00\x01\x00\x54\x21\x12\xa4\x42\x35\x59\x53\x6e\x42\x71\x70\x56\x77\x61\x39\x4f\x00\x06' 89 | b'\x00\x17\x70\x4c\x79\x5a\x48\x52\x3a\x47\x77\x4c\x33\x41\x48\x42\x6f\x76\x75\x62\x4c\x76' 90 | b'\x43\x71\x6e\x00\x80\x2a\x00\x08\x18\x8b\x10\x4c\x69\x7b\xf6\x5b\x00\x25\x00\x00\x00\x24' 91 | b'\x00\x04\x6e\x00\x1e\xff\x00\x08\x00\x14\x60\x2b\xc7\xfc\x0d\x10\x63\xaa\xc5\x38\x1c\xcb' 92 | b'\x96\xa9\x73\x08\x73\x9a\x96\x0c\x80\x28\x00\x04\xd1\x62\xea\x65') 93 | m = STUN(s) 94 | assert m.type == BINDING_REQUEST 95 | assert m.len == 84 96 | 97 | attrs = parse_attrs(m.data) 98 | assert len(attrs) == 6 99 | assert attrs[0] == (USERNAME, b'pLyZHR:GwL3AHBovubLvCqn') 100 | assert attrs[4][0] == MESSAGE_INTEGRITY 101 | -------------------------------------------------------------------------------- /dpkt/telnet.py: -------------------------------------------------------------------------------- 1 | # $Id: telnet.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Telnet.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | import struct 8 | 9 | from .compat import compat_ord 10 | 11 | IAC = 255 # interpret as command: 12 | DONT = 254 # you are not to use option 13 | DO = 253 # please, you use option 14 | WONT = 252 # I won't use option 15 | WILL = 251 # I will use option 16 | SB = 250 # interpret as subnegotiation 17 | GA = 249 # you may reverse the line 18 | EL = 248 # erase the current line 19 | EC = 247 # erase the current character 20 | AYT = 246 # are you there 21 | AO = 245 # abort output--but let prog finish 22 | IP = 244 # interrupt process--permanently 23 | BREAK = 243 # break 24 | DM = 242 # data mark--for connect. cleaning 25 | NOP = 241 # nop 26 | SE = 240 # end sub negotiation 27 | EOR = 239 # end of record (transparent mode) 28 | ABORT = 238 # Abort process 29 | SUSP = 237 # Suspend process 30 | xEOF = 236 # End of file: EOF is already used... 31 | 32 | SYNCH = 242 # for telfunc calls 33 | 34 | 35 | def strip_options(buf): 36 | """Return a list of lines and dict of options from telnet data.""" 37 | l_ = buf.split(struct.pack("B", IAC)) 38 | # print l_ 39 | b = [] 40 | d = {} 41 | subopt = False 42 | for w in l_: 43 | if not w: 44 | continue 45 | o = compat_ord(w[0]) 46 | if o > SB: 47 | # print 'WILL/WONT/DO/DONT/IAC', `w` 48 | w = w[2:] 49 | elif o == SE: 50 | # print 'SE', `w` 51 | w = w[1:] 52 | subopt = False 53 | elif o == SB: 54 | # print 'SB', `w` 55 | subopt = True 56 | for opt in (b'USER', b'DISPLAY', b'TERM'): 57 | p = w.find(opt + b'\x01') 58 | if p != -1: 59 | d[opt] = w[p + len(opt) + 1:].split(b'\x00', 1)[0] 60 | w = None 61 | elif subopt: 62 | w = None 63 | if w: 64 | w = w.replace(b'\x00', b'\n').splitlines() 65 | if not w[-1]: 66 | w.pop() 67 | b.extend(w) 68 | return b, d 69 | 70 | 71 | def test_telnet(): 72 | l_ = [] 73 | s = (b'\xff\xfb\x25\xff\xfa\x25\x00\x00\x00\xff\xf0\xff\xfd\x26\xff\xfa\x26\x05\xff\xf0\xff\xfa' 74 | b'\x26\x01\x01\x02\xff\xf0\xff\xfb\x18\xff\xfb\x20\xff\xfb\x23\xff\xfb\x27\xff\xfc\x24\xff' 75 | b'\xfa\x20\x00\x33\x38\x34\x30\x30\x2c\x33\x38\x34\x30\x30\xff\xf0\xff\xfa\x23\x00\x64\x6f' 76 | b'\x75\x67\x68\x62\x6f\x79\x2e\x63\x69\x74\x69\x2e\x75\x6d\x69\x63\x68\x2e\x65\x64\x75\x3a' 77 | b'\x30\x2e\x30\xff\xf0\xff\xfa\x27\x00\x00\x44\x49\x53\x50\x4c\x41\x59\x01\x64\x6f\x75\x67' 78 | b'\x68\x62\x6f\x79\x2e\x63\x69\x74\x69\x2e\x75\x6d\x69\x63\x68\x2e\x65\x64\x75\x3a\x30\x2e' 79 | b'\x30\x00\x55\x53\x45\x52\x01\x64\x75\x67\x73\x6f\x6e\x67\xff\xf0\xff\xfa\x18\x00\x58\x54' 80 | b'\x45\x52\x4d\xff\xf0\xff\xfd\x03\xff\xfc\x01\xff\xfb\x1f\xff\xfa\x1f\x00\x50\x00\x28\xff' 81 | b'\xf0\xff\xfd\x05\xff\xfb\x21\xff\xfd\x01\x66\x75\x67\x6c\x79\x0d\x00\x79\x6f\x64\x61\x0d' 82 | b'\x00\x62\x61\x73\x68\x74\x61\x72\x64\x0d\x00') 83 | l_.append(s) 84 | s = (b'\xff\xfd\x01\xff\xfd\x03\xff\xfb\x18\xff\xfb\x1f\xff\xfa\x1f\x00\x58\x00\x32\xff\xf0\x61' 85 | b'\x64\x6d\x69\x6e\x0d\x00\xff\xfa\x18\x00\x4c\x49\x4e\x55\x58\xff\xf0\x66\x6f\x6f\x62\x61' 86 | b'\x72\x0d\x00\x65\x6e\x61\x62\x6c\x65\x0d\x00\x66\x6f\x6f\x62\x61\x72\x0d\x00\x0d\x00\x73' 87 | b'\x68\x6f\x77\x20\x69\x70\x20\x69\x6e\x74\x20\x56\x6c\x61\x6e\x20\x36\x36\x36\x0d\x00') 88 | l_.append(s) 89 | s = (b'\xff\xfb\x25\xff\xfa\x25\x00\x00\x00\xff\xf0\xff\xfd\x26\xff\xfa\x26\x05\xff\xf0\xff\xfa' 90 | b'\x26\x01\x01\x02\xff\xf0\xff\xfb\x26\xff\xfb\x18\xff\xfb\x20\xff\xfb\x23\xff\xfb\x27\xff' 91 | b'\xfc\x24\xff\xfa\x20\x00\x33\x38\x34\x30\x30\x2c\x33\x38\x34\x30\x30\xff\xf0\xff\xfa\x23' 92 | b'\x00\x64\x6f\x75\x67\x68\x62\x6f\x79\x2e\x63\x69\x74\x69\x2e\x75\x6d\x69\x63\x68\x2e\x65' 93 | b'\x64\x75\x3a\x30\x2e\x30\xff\xf0\xff\xfa\x27\x00\x00\x44\x49\x53\x50\x4c\x41\x59\x01\x64' 94 | b'\x6f\x75\x67\x68\x62\x6f\x79\x2e\x63\x69\x74\x69\x2e\x75\x6d\x69\x63\x68\x2e\x65\x64\x75' 95 | b'\x3a\x30\x2e\x30\x00\x55\x53\x45\x52\x01\x64\x75\x67\x73\x6f\x6e\x67\xff\xf0\xff\xfa\x18' 96 | b'\x00\x58\x54\x45\x52\x4d\xff\xf0\xff\xfd\x03\xff\xfc\x01\xff\xfb\x22\xff\xfa\x22\x03\x01' 97 | b'\x03\x00\x03\x62\x03\x04\x02\x0f\x05\x00\xff\xff\x07\x62\x1c\x08\x02\x04\x09\x42\x1a\x0a' 98 | b'\x02\x7f\x0b\x02\x15\x0c\x02\x17\x0d\x02\x12\x0e\x02\x16\x0f\x02\x11\x10\x02\x13\x11\x00' 99 | b'\xff\xff\x12\x00\xff\xff\xff\xf0\xff\xfb\x1f\xff\xfa\x1f\x00\x50\x00\x28\xff\xf0\xff\xfd' 100 | b'\x05\xff\xfb\x21\xff\xfa\x22\x01\x0f\xff\xf0\xff\xfd\x01\xff\xfe\x01\xff\xfa\x22\x03\x01' 101 | b'\x80\x00\xff\xf0\xff\xfd\x01\x77\x65\x72\x64\x0d\x0a\xff\xfe\x01\x79\x6f\x64\x61\x0d\x0a' 102 | b'\xff\xfd\x01\x64\x61\x72\x74\x68\x76\x61\x64\x65\x72\x0d\x0a\xff\xfe\x01') 103 | l_.append(s) 104 | exp = [([b'fugly', b'yoda', b'bashtard'], {b'USER': b'dugsong', b'DISPLAY': b'doughboy.citi.umich.edu:0.0'}), 105 | ([b'admin', b'foobar', b'enable', b'foobar', b'', b'show ip int Vlan 666'], {}), 106 | ([b'werd', b'yoda', b'darthvader'], {b'USER': b'dugsong', b'DISPLAY': b'doughboy.citi.umich.edu:0.0'})] 107 | assert (list(map(strip_options, l_)) == exp) 108 | 109 | 110 | def test_trailing_null(): 111 | from binascii import unhexlify 112 | buf = unhexlify( 113 | '0100020000' 114 | ) 115 | b, d = strip_options(buf) 116 | assert b == [b'\x01', b'\x02'] 117 | assert d == {} 118 | -------------------------------------------------------------------------------- /dpkt/tftp.py: -------------------------------------------------------------------------------- 1 | # $Id: tftp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Trivial File Transfer Protocol.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | import struct 8 | 9 | from . import dpkt 10 | 11 | # Opcodes 12 | OP_RRQ = 1 # read request 13 | OP_WRQ = 2 # write request 14 | OP_DATA = 3 # data packet 15 | OP_ACK = 4 # acknowledgment 16 | OP_ERR = 5 # error code 17 | 18 | # Error codes 19 | EUNDEF = 0 # not defined 20 | ENOTFOUND = 1 # file not found 21 | EACCESS = 2 # access violation 22 | ENOSPACE = 3 # disk full or allocation exceeded 23 | EBADOP = 4 # illegal TFTP operation 24 | EBADID = 5 # unknown transfer ID 25 | EEXISTS = 6 # file already exists 26 | ENOUSER = 7 # no such user 27 | 28 | 29 | class TFTP(dpkt.Packet): 30 | """Trivial File Transfer Protocol. 31 | 32 | Trivial File Transfer Protocol (TFTP) is a simple lockstep File Transfer Protocol which allows a client to get 33 | a file from or put a file onto a remote host. One of its primary uses is in the early stages of nodes booting 34 | from a local area network. TFTP has been used for this application because it is very simple to implement. 35 | 36 | Attributes: 37 | __hdr__: Header fields of TFTP. 38 | opcode: Operation Code (2 bytes) 39 | """ 40 | 41 | __hdr__ = (('opcode', 'H', 1), ) 42 | 43 | def unpack(self, buf): 44 | dpkt.Packet.unpack(self, buf) 45 | if self.opcode in (OP_RRQ, OP_WRQ): 46 | l_ = self.data.split(b'\x00') 47 | self.filename = l_[0] 48 | self.mode = l_[1] 49 | self.data = b'' 50 | elif self.opcode in (OP_DATA, OP_ACK): 51 | self.block = struct.unpack('>H', self.data[:2])[0] 52 | self.data = self.data[2:] 53 | elif self.opcode == OP_ERR: 54 | self.errcode = struct.unpack('>H', self.data[:2])[0] 55 | self.errmsg = self.data[2:].split(b'\x00')[0] 56 | self.data = b'' 57 | 58 | def __len__(self): 59 | return len(bytes(self)) 60 | 61 | def __bytes__(self): 62 | if self.opcode in (OP_RRQ, OP_WRQ): 63 | s = self.filename + b'\x00' + self.mode + b'\x00' 64 | elif self.opcode in (OP_DATA, OP_ACK): 65 | s = struct.pack('>H', self.block) 66 | elif self.opcode == OP_ERR: 67 | s = struct.pack('>H', self.errcode) + (b'%s\x00' % self.errmsg) 68 | else: 69 | s = b'' 70 | return self.pack_hdr() + s + self.data 71 | 72 | 73 | def test_op_rrq(): 74 | from binascii import unhexlify 75 | buf = unhexlify( 76 | '0001' # opcode (OP_RRQ) 77 | '726663313335302e747874' # filename (rfc1350.txt) 78 | '00' # null terminator 79 | '6f63746574' # mode (octet) 80 | '00' # null terminator 81 | ) 82 | tftp = TFTP(buf) 83 | assert tftp.filename == b'rfc1350.txt' 84 | assert tftp.mode == b'octet' 85 | assert bytes(tftp) == buf 86 | assert len(tftp) == len(buf) 87 | 88 | 89 | def test_op_data(): 90 | from binascii import unhexlify 91 | buf = unhexlify( 92 | '0003' # opcode (OP_DATA) 93 | '0001' # block 94 | '0a0a4e6574776f726b20576f726b696e672047726f7570' 95 | ) 96 | tftp = TFTP(buf) 97 | assert tftp.block == 1 98 | assert tftp.data == b'\x0a\x0aNetwork Working Group' 99 | assert bytes(tftp) == buf 100 | assert len(tftp) == len(buf) 101 | 102 | 103 | def test_op_err(): 104 | from binascii import unhexlify 105 | buf = unhexlify( 106 | '0005' # opcode (OP_ERR) 107 | '0007' # errcode (ENOUSER) 108 | '0a0a4e6574776f726b20576f726b696e672047726f757000' 109 | ) 110 | tftp = TFTP(buf) 111 | assert tftp.errcode == ENOUSER 112 | assert tftp.errmsg == b'\x0a\x0aNetwork Working Group' 113 | assert tftp.data == b'' 114 | assert bytes(tftp) == buf 115 | 116 | 117 | def test_op_other(): 118 | from binascii import unhexlify 119 | buf = unhexlify( 120 | '0006' # opcode (doesn't exist) 121 | 'abcdef' # trailing data 122 | ) 123 | tftp = TFTP(buf) 124 | assert tftp.opcode == 6 125 | assert bytes(tftp) == buf 126 | assert tftp.data == unhexlify('abcdef') 127 | -------------------------------------------------------------------------------- /dpkt/tns.py: -------------------------------------------------------------------------------- 1 | # $Id: tns.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Transparent Network Substrate.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | 9 | 10 | class TNS(dpkt.Packet): 11 | """Transparent Network Substrate. 12 | 13 | TODO: Longer class information.... 14 | 15 | Attributes: 16 | __hdr__: Header fields of TNS. 17 | TODO. 18 | """ 19 | 20 | __hdr__ = ( 21 | ('length', 'H', 0), 22 | ('pktsum', 'H', 0), 23 | ('type', 'B', 0), 24 | ('rsvd', 'B', 0), 25 | ('hdrsum', 'H', 0), 26 | ('msg', '0s', b''), 27 | ) 28 | 29 | def unpack(self, buf): 30 | dpkt.Packet.unpack(self, buf) 31 | n = self.length - self.__hdr_len__ 32 | if n > len(self.data): 33 | raise dpkt.NeedData('short message (missing %d bytes)' % 34 | (n - len(self.data))) 35 | self.msg = self.data[:n] 36 | self.data = self.data[n:] 37 | 38 | 39 | def test_tns(): 40 | s = (b'\x00\x23\x00\x00\x01\x00\x00\x00\x01\x34\x01\x2c\x00\x00\x08\x00\x7f' 41 | b'\xff\x4f\x98\x00\x00\x00\x01\x00\x01\x00\x22\x00\x00\x00\x00\x01\x01X') 42 | t = TNS(s) 43 | assert t.msg.startswith(b'\x01\x34') 44 | 45 | # test a truncated packet 46 | try: 47 | t = TNS(s[:-10]) 48 | except dpkt.NeedData: 49 | pass 50 | -------------------------------------------------------------------------------- /dpkt/tpkt.py: -------------------------------------------------------------------------------- 1 | # $Id: tpkt.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """ISO Transport Service on top of the TCP (TPKT).""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | # TPKT - RFC 1006 Section 6 9 | # http://www.faqs.org/rfcs/rfc1006.html 10 | 11 | 12 | class TPKT(dpkt.Packet): 13 | """ISO Transport Service on top of the TCP (TPKT). 14 | 15 | "Emulate" ISO transport services COTP on top of TCP. The two major points missing in TCP (compared to COTP) 16 | are the TSAP addressing and the detection of packet boundaries on the receiving host. 17 | 18 | Attributes: 19 | __hdr__: Header fields of TPKT. 20 | v: (int): Version (1 byte) 21 | rsvd: (int): Reserved (1 byte) 22 | len: (int): Packet Length (2 bytes) 23 | """ 24 | 25 | __hdr__ = ( 26 | ('v', 'B', 3), 27 | ('rsvd', 'B', 0), 28 | ('len', 'H', 0) 29 | ) 30 | -------------------------------------------------------------------------------- /dpkt/udp.py: -------------------------------------------------------------------------------- 1 | # $Id: udp.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """User Datagram Protocol.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | UDP_HDR_LEN = 8 9 | UDP_PORT_MAX = 65535 10 | 11 | 12 | class UDP(dpkt.Packet): 13 | """User Datagram Protocol. 14 | 15 | User Datagram Protocol (UDP) is one of the core members of the Internet protocol suite. 16 | With UDP, computer applications can send messages, in this case referred to as datagrams, 17 | to other hosts on an Internet Protocol (IP) network. Prior communications are not required 18 | in order to set up communication channels or data paths. 19 | 20 | Attributes: 21 | __hdr__: Header fields of UDP. 22 | sport: (int): Source port. (2 bytes) 23 | dport: (int): Destination port. (2 bytes) 24 | ulen: (int): Length. (2 bytes) 25 | sum: (int): Checksum. (2 bytes) 26 | """ 27 | 28 | __hdr__ = ( 29 | ('sport', 'H', 0xdead), 30 | ('dport', 'H', 0), 31 | ('ulen', 'H', 8), 32 | ('sum', 'H', 0) 33 | ) 34 | -------------------------------------------------------------------------------- /dpkt/utils.py: -------------------------------------------------------------------------------- 1 | """Various Utility Functions""" 2 | import socket 3 | import warnings 4 | from .compat import compat_ord 5 | from .dns import DNS 6 | 7 | 8 | def mac_to_str(address): 9 | r"""Convert a MAC address to a readable/printable string 10 | 11 | Args: 12 | address (str): a MAC address in hex form (e.g. '\x01\x02\x03\x04\x05\x06') 13 | Returns: 14 | str: Printable/readable MAC address 15 | """ 16 | return ':'.join('%02x' % compat_ord(b) for b in address) 17 | 18 | 19 | def inet_to_str(inet): 20 | """Convert inet object to a string 21 | 22 | Args: 23 | inet (inet struct): inet network address 24 | Returns: 25 | str: Printable/readable IP address 26 | """ 27 | # First try ipv4 and then ipv6 28 | try: 29 | return socket.inet_ntop(socket.AF_INET, inet) 30 | except ValueError: 31 | return socket.inet_ntop(socket.AF_INET6, inet) 32 | 33 | 34 | def make_dict(obj): 35 | """Create a dictionary out of a non-builtin object""" 36 | # Recursion base case 37 | if is_builtin(obj): 38 | return obj 39 | 40 | output_dict = {} 41 | for key in dir(obj): 42 | if not key.startswith('__') and not callable(getattr(obj, key)): 43 | attr = getattr(obj, key) 44 | if isinstance(attr, list): 45 | output_dict[key] = [] 46 | for item in attr: 47 | output_dict[key].append(make_dict(item)) 48 | else: 49 | output_dict[key] = make_dict(attr) 50 | 51 | return output_dict 52 | 53 | 54 | def is_builtin(obj): 55 | return obj.__class__.__module__ in ['__builtin__', 'builtins'] 56 | 57 | 58 | def deprecation_warning(*args): 59 | """print a deprecation warning""" 60 | warnings.warn(*args, stacklevel=2) 61 | 62 | 63 | def test_utils(): 64 | """Test the utility methods""" 65 | from binascii import unhexlify 66 | from pprint import pprint 67 | 68 | print(mac_to_str(b'\x01\x02\x03\x04\x05\x06')) 69 | assert mac_to_str(b'\x01\x02\x03\x04\x05\x06') == '01:02:03:04:05:06' 70 | print(inet_to_str(b'\x91\xfe\xa0\xed')) 71 | assert inet_to_str(b'\x91\xfe\xa0\xed') == '145.254.160.237' 72 | ipv6_inet = b' \x01\r\xb8\x85\xa3\x00\x00\x00\x00\x8a.\x03ps4' 73 | assert inet_to_str(ipv6_inet) == '2001:db8:85a3::8a2e:370:7334' 74 | 75 | # Test the make_dict method with a DNS response packet 76 | a_resp = unhexlify("059c8180000100010000000106676f6f676c6503636f6d0000010001c00c00010" 77 | "0010000012b0004d83ace2e0000290200000000000000") 78 | my_dns = DNS(a_resp) 79 | pprint(make_dict(my_dns)) 80 | -------------------------------------------------------------------------------- /dpkt/vrrp.py: -------------------------------------------------------------------------------- 1 | # $Id: vrrp.py 88 2013-03-05 19:43:17Z andrewflnr@gmail.com $ 2 | # -*- coding: utf-8 -*- 3 | """Virtual Router Redundancy Protocol.""" 4 | from __future__ import print_function 5 | from __future__ import absolute_import 6 | 7 | from . import dpkt 8 | 9 | 10 | class VRRP(dpkt.Packet): 11 | """Virtual Router Redundancy Protocol. 12 | 13 | TODO: Longer class information.... 14 | 15 | Attributes: 16 | __hdr__: Header fields of VRRP. 17 | TODO. 18 | """ 19 | 20 | __hdr__ = ( 21 | ('_v_type', 'B', 0x21), 22 | ('vrid', 'B', 0), 23 | ('priority', 'B', 0), 24 | ('count', 'B', 0), 25 | ('atype', 'B', 0), 26 | ('advtime', 'B', 0), 27 | ('sum', 'H', 0), 28 | ) 29 | __bit_fields__ = { 30 | '_v_type': ( 31 | ('v', 4), 32 | ('type', 4), 33 | ) 34 | } 35 | 36 | addrs = () 37 | auth = '' 38 | 39 | def unpack(self, buf): 40 | dpkt.Packet.unpack(self, buf) 41 | l_ = [] 42 | off = 0 43 | for off in range(0, 4 * self.count, 4): 44 | l_.append(self.data[off:off + 4]) 45 | self.addrs = l_ 46 | self.auth = self.data[off + 4:] 47 | self.data = '' 48 | 49 | def __len__(self): 50 | return self.__hdr_len__ + (4 * self.count) + len(self.auth) 51 | 52 | def __bytes__(self): 53 | data = b''.join(self.addrs) + self.auth 54 | if not self.sum: 55 | self.sum = dpkt.in_cksum(self.pack_hdr() + data) 56 | return self.pack_hdr() + data 57 | 58 | 59 | def test_vrrp(): 60 | # no addresses 61 | s = b'\x00\x00\x00\x00\x00\x00\xff\xff' 62 | v = VRRP(s) 63 | assert v.sum == 0xffff 64 | assert bytes(v) == s 65 | 66 | # have address 67 | s = b'\x21\x01\x64\x01\x00\x01\xba\x52\xc0\xa8\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00' 68 | v = VRRP(s) 69 | assert v.count == 1 70 | assert v.addrs == [b'\xc0\xa8\x00\x01'] # 192.168.0.1 71 | assert bytes(v) == s 72 | 73 | # test checksum generation 74 | v.sum = 0 75 | assert bytes(v) == s 76 | 77 | # test length 78 | assert len(v) == len(s) 79 | 80 | # test getters 81 | assert v.v == 2 82 | assert v.type == 1 83 | 84 | # test setters 85 | v.v = 3 86 | v.type = 2 87 | assert bytes(v)[0] == b'\x32'[0] 88 | -------------------------------------------------------------------------------- /dpkt/yahoo.py: -------------------------------------------------------------------------------- 1 | # $Id: yahoo.py 23 2006-11-08 15:45:33Z dugsong $ 2 | # -*- coding: utf-8 -*- 3 | """Yahoo Messenger.""" 4 | from __future__ import absolute_import 5 | 6 | from . import dpkt 7 | 8 | 9 | class YHOO(dpkt.Packet): 10 | """Yahoo Messenger. 11 | 12 | Yahoo! Messenger (sometimes abbreviated Y!M) was an advertisement-supported instant messaging client and associated 13 | protocol provided by Yahoo!. Yahoo! Messenger was provided free of charge and could be downloaded and used with a 14 | generic "Yahoo ID" which also allowed access to other Yahoo! services, such as Yahoo! Mail. The service also 15 | offered VoIP, file transfers, webcam hosting, a text messaging service, and chat rooms in various categories. 16 | 17 | Attributes: 18 | __hdr__: Header fields of Yahoo Messenger. 19 | version: (bytes): Version. (8 bytes) 20 | length: (int): Length. (4 bytes) 21 | service: (int): Service. (4 bytes) 22 | connid: (int): Connection ID. (4 bytes) 23 | magic: (int): Magic. (4 bytes) 24 | unknown: (int): Unknown. (4 bytes) 25 | type: (int): Type. (4 bytes) 26 | nick1: (bytes): Nick1. (36 bytes) 27 | nick2: (bytes): Nick2. (36 bytes) 28 | """ 29 | 30 | __hdr__ = [ 31 | ('version', '8s', ' ' * 8), 32 | ('length', 'I', 0), 33 | ('service', 'I', 0), 34 | ('connid', 'I', 0), 35 | ('magic', 'I', 0), 36 | ('unknown', 'I', 0), 37 | ('type', 'I', 0), 38 | ('nick1', '36s', ' ' * 36), 39 | ('nick2', '36s', ' ' * 36) 40 | ] 41 | __byte_order__ = '<' 42 | 43 | 44 | class YMSG(dpkt.Packet): 45 | __hdr__ = [ 46 | ('version', '8s', ' ' * 8), 47 | ('length', 'H', 0), 48 | ('type', 'H', 0), 49 | ('unknown1', 'I', 0), 50 | ('unknown2', 'I', 0) 51 | ] 52 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbandla/dpkt/4f8958eb4b375b38d0ab6ffadf2da9b24395394d/examples/__init__.py -------------------------------------------------------------------------------- /examples/data/README.md: -------------------------------------------------------------------------------- 1 | ### PCAP Data 2 | A good resource for PCAP data is : [https://wiki.wireshark.org/SampleCaptures]() 3 | 4 | - #### http.pcap: 5 | A simple HTTP request and response 6 | 7 | - #### nb6-http.pcap: 8 | provided by french ISP SFR, there are three different HTTP requests: first was sent on the private IPv4 network (IPoE), second was sent on the public IPv4 network, third was sent on the public IPv6 network (L2TP tunnel). 9 | 10 | -------------------------------------------------------------------------------- /examples/data/dns_icmp.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbandla/dpkt/4f8958eb4b375b38d0ab6ffadf2da9b24395394d/examples/data/dns_icmp.pcap -------------------------------------------------------------------------------- /examples/data/http.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbandla/dpkt/4f8958eb4b375b38d0ab6ffadf2da9b24395394d/examples/data/http.pcap -------------------------------------------------------------------------------- /examples/data/nb6-http.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbandla/dpkt/4f8958eb4b375b38d0ab6ffadf2da9b24395394d/examples/data/nb6-http.pcap -------------------------------------------------------------------------------- /examples/data/truncated_dns.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbandla/dpkt/4f8958eb4b375b38d0ab6ffadf2da9b24395394d/examples/data/truncated_dns.pcap -------------------------------------------------------------------------------- /examples/data/truncated_dns_2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kbandla/dpkt/4f8958eb4b375b38d0ab6ffadf2da9b24395394d/examples/data/truncated_dns_2.pcap -------------------------------------------------------------------------------- /examples/old/dhcprequest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | import sys 5 | import socket 6 | 7 | # Since pcapy is not a requirement of dpkt, test the import and give message 8 | try: 9 | import pcapy 10 | except ImportError: 11 | print('Could not import pcapy. Please do a $pip install pcapy') 12 | sys.exit(1) 13 | 14 | # dpkt imports 15 | from dpkt import dhcp 16 | from dpkt import udp 17 | from dpkt import ip 18 | from dpkt import ethernet 19 | 20 | # Grab the default interface and use that for the injection 21 | devices = pcapy.findalldevs() 22 | iface_name = devices[0] 23 | print('Auto Setting Interface to: {:s}'.format(iface_name)) 24 | interface = pcapy.open_live(iface_name, 65536, 1, 0) 25 | 26 | # Get local ip 27 | src_ip = socket.inet_pton(socket.AF_INET, interface.getnet()) 28 | 29 | # Generate broadcast ip and eth_addr 30 | broadcast_ip = socket.inet_pton(socket.AF_INET, '255.255.255.255') 31 | broadcast_eth_addr = b'\xFF\xFF\xFF\xFF\xFF\xFF' 32 | 33 | # build a dhcp discover packet to request an ip 34 | d = dhcp.DHCP( 35 | xid=1337, 36 | op=dhcp.DHCPDISCOVER, 37 | opts=( 38 | (dhcp.DHCP_OP_REQUEST, b''), 39 | (dhcp.DHCP_OPT_REQ_IP, b''), 40 | (dhcp.DHCP_OPT_ROUTER, b''), 41 | (dhcp.DHCP_OPT_NETMASK, b''), 42 | (dhcp.DHCP_OPT_DNS_SVRS, b'') 43 | ) 44 | ) 45 | 46 | # build udp packet 47 | u = udp.UDP( 48 | dport=67, 49 | sport=68, 50 | data=d 51 | ) 52 | u.ulen = len(u) 53 | 54 | # build ip packet 55 | i = ip.IP( 56 | dst=broadcast_ip, 57 | src=src_ip, 58 | data=u, 59 | p=ip.IP_PROTO_UDP 60 | ) 61 | i.len = len(i) 62 | 63 | # build ethernet frame 64 | e = ethernet.Ethernet( 65 | dst=broadcast_eth_addr, 66 | data=i 67 | ) 68 | 69 | # Inject the packet (send it out) 70 | interface.sendpacket(bytes(e)) 71 | 72 | print('DHCP request sent!') 73 | -------------------------------------------------------------------------------- /examples/old/dnsping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | 5 | import random 6 | import socket 7 | import dpkt 8 | import ping 9 | 10 | 11 | class DNSPing(ping.Ping): 12 | def __init__(self): 13 | ping.Ping.__init__(self) 14 | self.op.add_option('-z', dest='zone', type='string', 15 | default=socket.gethostname().split('.', 1)[1], 16 | help='Domain to formulate queries in') 17 | self.op.add_option('-n', dest='hostname', type='string', 18 | help='Query only for a given hostname') 19 | self.op.add_option('-p', dest='port', type='int', default=53, 20 | help='Remote DNS server port') 21 | self.op.add_option('-R', dest='norecurse', action='store_true', 22 | help='Disable recursive queries') 23 | 24 | def open_sock(self, opts): 25 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 26 | sock.connect((opts.ip, opts.port)) 27 | sock.settimeout(opts.wait) 28 | return sock 29 | 30 | def gen_ping(self, opts): 31 | for i in range(opts.count): 32 | dns = dpkt.dns.DNS(id=i) 33 | if opts.norecurse: 34 | dns.op &= ~dpkt.dns.DNS_RD 35 | if not opts.hostname: 36 | name = '%s.%s' % (str(random.random())[-6:], opts.zone) 37 | else: 38 | name = opts.hostname 39 | dns.qd = [dpkt.dns.DNS.Q(name=name)] 40 | yield str(dns) 41 | 42 | def print_header(self, opts): 43 | print('DNSPING %s:' % opts.ip, end='') 44 | if opts.hostname: 45 | print('Name: %s' % opts.hostname) 46 | else: 47 | print('Name: *.%s' % opts.zone) 48 | 49 | def print_reply(self, opts, buf, rtt): 50 | dns = dpkt.dns.DNS(buf) 51 | print('%d bytes from %s: id=%d time=%.3f ms' % 52 | (len(buf), opts.ip, dns.id, rtt * 1000)) 53 | 54 | 55 | if __name__ == '__main__': 56 | DNSPing().main() 57 | -------------------------------------------------------------------------------- /examples/old/nbtping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import socket 4 | from dpkt import netbios 5 | import ping 6 | 7 | 8 | class NBTPing(ping.Ping): 9 | def __init__(self): 10 | ping.Ping.__init__(self) 11 | self.op.add_option('-p', dest='port', type='int', default=137, 12 | help='Remote NetBIOS name server port') 13 | 14 | def open_sock(self, opts): 15 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 16 | sock.connect((opts.ip, opts.port)) 17 | sock.settimeout(opts.wait) 18 | return sock 19 | 20 | def gen_ping(self, opts): 21 | for i in range(opts.count): 22 | ns = netbios.NS(id=i, 23 | qd=[netbios.NS.Q(type=netbios.NS_NBSTAT, name='*')]) 24 | yield str(ns) 25 | 26 | def print_header(self, opts): 27 | print('NBTPING %s:' % opts.ip) 28 | 29 | def print_reply(self, opts, buf, rtt): 30 | ns = netbios.NS(buf) 31 | d = {} 32 | for rr in ns.an: 33 | for name, svc, flags in rr.nodenames: 34 | unique = (flags & netbios.NS_NAME_G == 0) 35 | if svc == 0 and unique and 'host' not in d: 36 | d['host'] = name 37 | elif svc == 0x03 and unique: 38 | if 'user' not in d or d['user'].startswith(d['host']): 39 | d['user'] = name 40 | print('%d bytes from %s: id=%d time=%.3f ms host=%s user=%s' % 41 | (len(buf), opts.ip, ns.id, rtt * 1000, 42 | d.get('host', ''), d.get('user', ''))) 43 | 44 | 45 | if __name__ == '__main__': 46 | NBTPing().main() 47 | -------------------------------------------------------------------------------- /examples/old/ping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import math 4 | import optparse 5 | import random 6 | import socket 7 | import sys 8 | import time 9 | import dpkt 10 | 11 | 12 | class Ping(object): 13 | def __init__(self): 14 | usage = '%prog [OPTIONS] ' 15 | self.op = optparse.OptionParser(usage=usage) 16 | self.op.add_option('-c', dest='count', type='int', default=sys.maxint, 17 | help='Total number of queries to send') 18 | self.op.add_option('-i', dest='wait', type='float', default=1, 19 | help='Specify packet interval timeout in seconds') 20 | 21 | def gen_ping(self, opts): 22 | pass 23 | 24 | def open_sock(self, opts): 25 | pass 26 | 27 | def print_header(self, opts): 28 | pass 29 | 30 | def print_reply(self, opts, buf, rtt): 31 | pass 32 | 33 | def main(self, argv=None): 34 | if not argv: 35 | argv = sys.argv[1:] 36 | opts, args = self.op.parse_args(argv) 37 | 38 | if not args: 39 | self.op.error('missing host') 40 | elif len(args) > 1: 41 | self.op.error('only one host may be specified') 42 | 43 | host = args[0] 44 | opts.ip = socket.gethostbyname(host) 45 | sock = self.open_sock(opts) 46 | 47 | sent = rcvd = rtt_max = rtt_sum = rtt_sumsq = 0 48 | rtt_min = 0xffff 49 | try: 50 | self.print_header(opts) 51 | for ping in self.gen_ping(opts): 52 | try: 53 | start = time.time() 54 | sock.send(ping) 55 | buf = sock.recv(0xffff) 56 | rtt = time.time() - start 57 | 58 | if rtt < rtt_min: 59 | rtt_min = rtt 60 | if rtt > rtt_max: 61 | rtt_max = rtt 62 | rtt_sum += rtt 63 | rtt_sumsq += rtt * rtt 64 | 65 | self.print_reply(opts, buf, rtt) 66 | rcvd += 1 67 | except socket.timeout: 68 | pass 69 | sent += 1 70 | time.sleep(opts.wait) 71 | except KeyboardInterrupt: 72 | pass 73 | 74 | print('\n--- %s ping statistics ---' % opts.ip) 75 | print('%d packets transmitted, %d packets received, %.1f%% packet loss' % 76 | (sent, rcvd, (float(sent - rcvd) / sent) * 100)) 77 | rtt_avg = rtt_sum / sent 78 | if rtt_min == 0xffff: 79 | rtt_min = 0 80 | print('round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms' % 81 | (rtt_min * 1000, rtt_avg * 1000, rtt_max * 1000, 82 | math.sqrt((rtt_sumsq / sent) - (rtt_avg * rtt_avg)) * 1000)) 83 | 84 | 85 | class ICMPPing(Ping): 86 | def __init__(self): 87 | Ping.__init__(self) 88 | self.op.add_option('-p', dest='payload', type='string', 89 | default='hello world!', 90 | help='Echo payload string') 91 | 92 | def open_sock(self, opts): 93 | sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, 1) 94 | sock.connect((opts.ip, 1)) 95 | sock.settimeout(opts.wait) 96 | return sock 97 | 98 | def gen_ping(self, opts): 99 | for i in range(opts.count): 100 | icmp = dpkt.icmp.ICMP( 101 | type=8, data=dpkt.icmp.ICMP.Echo(id=random.randint(0, 0xffff), 102 | seq=i, data=opts.payload)) 103 | yield str(icmp) 104 | 105 | def print_header(self, opts): 106 | print('PING %s: %d data bytes' % (opts.ip, len(opts.payload))) 107 | 108 | def print_reply(self, opts, buf, rtt): 109 | ip = dpkt.ip.IP(buf) 110 | if sys.platform == 'darwin': 111 | # XXX - work around raw socket bug on MacOS X 112 | ip.data = ip.icmp = dpkt.icmp.ICMP(buf[20:]) 113 | ip.len = len(ip.data) 114 | print('%d bytes from %s: icmp_seq=%d ip_id=%d ttl=%d time=%.3f ms' % 115 | (len(ip.icmp), opts.ip, ip.icmp.echo.seq, ip.id, ip.ttl, 116 | rtt * 1000)) 117 | 118 | 119 | if __name__ == '__main__': 120 | p = ICMPPing() 121 | p.main() 122 | -------------------------------------------------------------------------------- /examples/print_dns_truncated.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use DPKT to read in a pcap file and print out the contents of truncated 3 | DNS packets. This example show how to read/handle truncated packets 4 | """ 5 | import sys 6 | import dpkt 7 | import datetime 8 | from dpkt.utils import mac_to_str, inet_to_str, make_dict 9 | from pprint import pprint 10 | 11 | 12 | def print_packet(buf): 13 | """Print out information about each packet in a pcap 14 | 15 | Args: 16 | buf: buffer of bytes for this packet 17 | """ 18 | print(type(buf)) 19 | 20 | # Unpack the Ethernet frame (mac src/dst, ethertype) 21 | eth = dpkt.ethernet.Ethernet(buf) 22 | print('Ethernet Frame: ', mac_to_str(eth.src), mac_to_str(eth.dst), eth.type) 23 | 24 | # Make sure the Ethernet data contains an IP packet 25 | if not isinstance(eth.data, dpkt.ip.IP): 26 | print('Non IP Packet type not supported %s\n' % eth.data.__class__.__name__) 27 | return 28 | 29 | # Now unpack the data within the Ethernet frame (the IP packet) 30 | # Pulling out src, dst, length, fragment info, TTL, and Protocol 31 | ip = eth.data 32 | 33 | # Pull out fragment information (flags and offset all packed into off field, so use bitmasks) 34 | do_not_fragment = bool(ip.off & dpkt.ip.IP_DF) 35 | more_fragments = bool(ip.off & dpkt.ip.IP_MF) 36 | fragment_offset = ip.off & dpkt.ip.IP_OFFMASK 37 | 38 | # Print out the info 39 | print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)' % 40 | (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, 41 | more_fragments, fragment_offset)) 42 | 43 | # Check for UDP in the transport layer 44 | if isinstance(ip.data, dpkt.udp.UDP): 45 | 46 | # Set the UDP data 47 | udp = ip.data 48 | print('UDP: sport={:d} dport={:d} sum={:d} ulen={:d}'.format(udp.sport, udp.dport, 49 | udp.sum, udp.ulen)) 50 | 51 | # Now see if we can parse the contents of the truncated DNS request 52 | try: 53 | dns = dpkt.dns.DNS() 54 | dns.unpack(udp.data) 55 | except (dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError, Exception) as e: 56 | print('\nError Parsing DNS, Might be a truncated packet...') 57 | print('Exception: {!r}'.format(e)) 58 | 59 | # Print out the DNS info 60 | print('Queries: {:d}'.format(len(dns.qd))) 61 | for query in dns.qd: 62 | print('\t {:s} Type:{:d}'.format(query.name, query.type)) 63 | print('Answers: {:d}'.format(len(dns.an))) 64 | for answer in dns.an: 65 | if answer.type == 5: 66 | print('\t {:s}: type: CNAME Answer: {:s}'.format(answer.name, answer.cname)) 67 | elif answer.type == 1: 68 | print('\t {:s}: type: A Answer: {:s}'.format(answer.name, inet_to_str(answer.ip))) 69 | else: 70 | pprint(make_dict(answer)) 71 | 72 | 73 | def process_packets(pcap): 74 | """Process each packet in a pcap 75 | 76 | Args: 77 | pcap: dpkt pcap reader object (dpkt.pcap.Reader) 78 | """ 79 | # For each packet in the pcap process the contents 80 | try: 81 | for timestamp, buf in pcap: 82 | # Print out the timestamp in UTC 83 | print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))) 84 | print_packet(buf) 85 | except dpkt.dpkt.NeedData: 86 | print('\nPCAP capture is truncated, stopping processing...') 87 | sys.exit(1) 88 | 89 | 90 | def test(): 91 | """Open up a test pcap file and print out the packets""" 92 | with open('data/truncated_dns_2.pcap', 'rb') as f: 93 | pcap = dpkt.pcap.Reader(f) 94 | process_packets(pcap) 95 | 96 | 97 | if __name__ == '__main__': 98 | test() 99 | -------------------------------------------------------------------------------- /examples/print_http_requests.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example expands on the print_packets example. It checks for HTTP request headers and displays their contents. 3 | NOTE: We are not reconstructing 'flows' so the request (and response if you tried to parse it) will only 4 | parse correctly if they fit within a single packet. Requests can often fit in a single packet but 5 | Responses almost never will. For proper reconstruction of flows you may want to look at other projects 6 | that use DPKT (http://chains.readthedocs.io and others) 7 | """ 8 | import dpkt 9 | import datetime 10 | from dpkt.utils import mac_to_str, inet_to_str 11 | 12 | 13 | def print_http_requests(pcap): 14 | """Print out information about each packet in a pcap 15 | 16 | Args: 17 | pcap: dpkt pcap reader object (dpkt.pcap.Reader) 18 | """ 19 | # For each packet in the pcap process the contents 20 | for timestamp, buf in pcap: 21 | 22 | # Unpack the Ethernet frame (mac src/dst, ethertype) 23 | eth = dpkt.ethernet.Ethernet(buf) 24 | 25 | # Make sure the Ethernet data contains an IP packet 26 | if not isinstance(eth.data, dpkt.ip.IP): 27 | print('Non IP Packet type not supported %s\n' % eth.data.__class__.__name__) 28 | continue 29 | 30 | # Now grab the data within the Ethernet frame (the IP packet) 31 | ip = eth.data 32 | 33 | # Check for TCP in the transport layer 34 | if isinstance(ip.data, dpkt.tcp.TCP): 35 | 36 | # Set the TCP data 37 | tcp = ip.data 38 | 39 | # Now see if we can parse the contents as a HTTP request 40 | try: 41 | request = dpkt.http.Request(tcp.data) 42 | except (dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError): 43 | continue 44 | 45 | # Pull out fragment information (flags and offset all packed into off field, so use bitmasks) 46 | do_not_fragment = bool(ip.off & dpkt.ip.IP_DF) 47 | more_fragments = bool(ip.off & dpkt.ip.IP_MF) 48 | fragment_offset = ip.off & dpkt.ip.IP_OFFMASK 49 | 50 | # Print out the info 51 | print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))) 52 | print('Ethernet Frame: ', mac_to_str(eth.src), mac_to_str(eth.dst), eth.type) 53 | print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)' % 54 | (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, more_fragments, fragment_offset)) 55 | print('HTTP request: %s\n' % repr(request)) 56 | 57 | # Check for Header spanning acrossed TCP segments 58 | if not tcp.data.endswith(b'\r\n'): 59 | print('\nHEADER TRUNCATED! Reassemble TCP segments!\n') 60 | 61 | 62 | def test(): 63 | """Open up a test pcap file and print out the packets""" 64 | with open('data/http.pcap', 'rb') as f: 65 | pcap = dpkt.pcap.Reader(f) 66 | print_http_requests(pcap) 67 | 68 | 69 | if __name__ == '__main__': 70 | test() 71 | -------------------------------------------------------------------------------- /examples/print_icmp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | This example expands on the print_packets example. It checks for ICMP packets and displays the ICMP contents. 4 | """ 5 | import dpkt 6 | import datetime 7 | from dpkt.utils import mac_to_str, inet_to_str 8 | 9 | 10 | def print_icmp(pcap): 11 | """Print out information about each packet in a pcap 12 | 13 | Args: 14 | pcap: dpkt pcap reader object (dpkt.pcap.Reader) 15 | """ 16 | # For each packet in the pcap process the contents 17 | for timestamp, buf in pcap: 18 | 19 | # Unpack the Ethernet frame (mac src/dst, ethertype) 20 | eth = dpkt.ethernet.Ethernet(buf) 21 | 22 | # Make sure the Ethernet data contains an IP packet 23 | if not isinstance(eth.data, dpkt.ip.IP): 24 | print('Non IP Packet type not supported %s\n' % eth.data.__class__.__name__) 25 | continue 26 | 27 | # Now grab the data within the Ethernet frame (the IP packet) 28 | ip = eth.data 29 | 30 | # Now check if this is an ICMP packet 31 | if isinstance(ip.data, dpkt.icmp.ICMP): 32 | icmp = ip.data 33 | 34 | # Pull out fragment information (flags and offset all packed into off field, so use bitmasks) 35 | do_not_fragment = bool(ip.off & dpkt.ip.IP_DF) 36 | more_fragments = bool(ip.off & dpkt.ip.IP_MF) 37 | fragment_offset = ip.off & dpkt.ip.IP_OFFMASK 38 | 39 | # Print out the info 40 | print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))) 41 | print('Ethernet Frame: ', mac_to_str(eth.src), mac_to_str(eth.dst), eth.type) 42 | print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)' % 43 | (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, 44 | do_not_fragment, more_fragments, fragment_offset)) 45 | print('ICMP: type:%d code:%d checksum:%d data: %s\n' % 46 | (icmp.type, icmp.code, icmp.sum, repr(icmp.data))) 47 | 48 | 49 | def test(): 50 | """Open up a test pcap file and print out the packets""" 51 | with open('data/dns_icmp.pcap', 'rb') as f: 52 | pcap = dpkt.pcap.Reader(f) 53 | print_icmp(pcap) 54 | 55 | 56 | if __name__ == '__main__': 57 | test() 58 | -------------------------------------------------------------------------------- /examples/print_packets.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use DPKT to read in a pcap file and print out the contents of the packets. 3 | This example is focused on the fields in the Ethernet Frame and IP packet. 4 | """ 5 | import dpkt 6 | import datetime 7 | from dpkt.utils import mac_to_str, inet_to_str 8 | 9 | 10 | def print_packets(pcap): 11 | """Print out information about each packet in a pcap 12 | 13 | Args: 14 | pcap: dpkt pcap reader object (dpkt.pcap.Reader) 15 | """ 16 | # For each packet in the pcap process the contents 17 | for timestamp, buf in pcap: 18 | 19 | # Print out the timestamp in UTC 20 | print('Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))) 21 | 22 | # Unpack the Ethernet frame (mac src/dst, ethertype) 23 | eth = dpkt.ethernet.Ethernet(buf) 24 | print('Ethernet Frame: ', mac_to_str(eth.src), mac_to_str(eth.dst), eth.type) 25 | 26 | # Make sure the Ethernet data contains an IP packet 27 | if not isinstance(eth.data, dpkt.ip.IP): 28 | print('Non IP Packet type not supported %s\n' % eth.data.__class__.__name__) 29 | continue 30 | 31 | # Now access the data within the Ethernet frame (the IP packet) 32 | # Pulling out src, dst, length, fragment info, TTL, and Protocol 33 | ip = eth.data 34 | 35 | # Print out the info, including the fragment flags and offset 36 | print('IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)\n' % 37 | (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, ip.df, ip.mf, ip.offset)) 38 | 39 | # Pretty print the last packet 40 | print('** Pretty print demo **\n') 41 | eth.pprint() 42 | 43 | 44 | def test(): 45 | """Open up a test pcap file and print out the packets""" 46 | with open('data/http.pcap', 'rb') as f: 47 | pcap = dpkt.pcap.Reader(f) 48 | print_packets(pcap) 49 | 50 | 51 | if __name__ == '__main__': 52 | test() 53 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | 3 | [aliases] 4 | release = sdist bdist_wheel upload -r pypi 5 | test_release = sdist bdist_wheel upload -r pypitest 6 | 7 | [flake8] 8 | max-line-length = 140 9 | 10 | [tool:pytest] 11 | addopts= -v --cov-report term-missing 12 | python_files=*.py 13 | python_functions=test 14 | norecursedirs=.tox .git *.egg-info __pycache__ dist build 15 | 16 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | try: 4 | from setuptools import setup 5 | except ImportError: 6 | from distutils.core import setup 7 | 8 | package_name = 'dpkt' 9 | description = 'fast, simple packet creation / parsing, with definitions for the basic TCP/IP protocols' 10 | readme = open('README.md').read() 11 | requirements = [] 12 | 13 | # PyPI Readme 14 | long_description = open('README.md').read() 15 | 16 | # Pull in the package 17 | package = __import__(package_name) 18 | package_version = package.__version__ 19 | if "bdist_msi" in sys.argv: 20 | # The MSI build target does not support a 4 digit version, e.g. '1.2.3.4' 21 | # therefore we remove the last digit. 22 | package_version, _, _ = package_version.rpartition('.') 23 | 24 | setup(name=package_name, 25 | version=package_version, 26 | author=package.__author__, 27 | author_email=package.__author_email__, 28 | url=package.__url__, 29 | description=description, 30 | long_description=long_description, 31 | long_description_content_type='text/markdown', 32 | packages=['dpkt'], 33 | install_requires=requirements, 34 | license='BSD', 35 | zip_safe=False, 36 | classifiers=[ 37 | 'Development Status :: 4 - Beta', 38 | 'Intended Audience :: Developers', 39 | 'License :: OSI Approved :: BSD License', 40 | 'Natural Language :: English', 41 | 'Programming Language :: Python :: 2.7', 42 | 'Programming Language :: Python :: 3.5', 43 | 'Programming Language :: Python :: 3.6', 44 | 'Programming Language :: Python :: 3.7', 45 | 'Programming Language :: Python :: 3.8', 46 | 'Programming Language :: Python :: 3.9', 47 | 'Programming Language :: Python :: Implementation :: CPython', 48 | 'Programming Language :: Python :: Implementation :: PyPy', 49 | ]) 50 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py35, py36, py37, py38 3 | 4 | [testenv] 5 | install_command = 6 | pip install {opts} {packages} 7 | deps = 8 | pytest 9 | coverage 10 | pytest-cov 11 | commands = 12 | py.test {posargs:--cov=dpkt dpkt} 13 | 14 | [testenv:style] 15 | deps = 16 | flake8 17 | commands = 18 | python setup.py flake8 19 | 20 | [testenv:coveralls] 21 | passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH 22 | deps = 23 | coveralls 24 | usedevelop = true 25 | commands = 26 | coverage report 27 | coveralls 28 | 29 | [coverage:run] 30 | relative_files = True 31 | command_line = -m pytest dpkt 32 | 33 | [coverage:report] 34 | exclude_lines = 35 | @abstractmethod 36 | --------------------------------------------------------------------------------