[
  {
    "path": ".github/workflows/release.yml",
    "content": "# This workflow will build a golang project\n# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go\n\nname: Release\n\non:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\njobs:\n\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        goosarch:\n          - 'linux/amd64'\n          - 'linux/386'\n          - 'darwin/amd64'\n          - 'darwin/arm64'\n          - 'windows/amd64'\n          - 'windows/386'\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-go@v2\n        with:\n          go-version: '1.17'\n      - name: Get OS and arch info\n        run: |\n          GOOSARCH=${{matrix.goosarch}}\n          GOOS=${GOOSARCH%/*}\n          GOARCH=${GOOSARCH#*/}\n          BINARY_NAME=${{github.event.repository.name}}-$GOOS-$GOARCH\n          echo \"BINARY_NAME=$BINARY_NAME\" >> $GITHUB_ENV\n          echo \"GOOS=$GOOS\" >> $GITHUB_ENV\n          echo \"GOARCH=$GOARCH\" >> $GITHUB_ENV\n      - name: Build\n        run: |\n          go build -o \"$BINARY_NAME\" -v ./cmd/udpx\n\n      - name: Zip bin\n        run: zip -r ${{env.BINARY_NAME}}.zip ${{env.BINARY_NAME}}\n\n      #- name: Release Notes\n      #  run:\n      #    git log $(git describe HEAD~ --tags --abbrev=0)..HEAD --pretty='format:* %h %s%n  * %an <%ae>' --no-merges >> \".github/RELEASE-TEMPLATE.md\"\n      - name: Release with Notes\n        uses: softprops/action-gh-release@v1\n        with:\n          tag_name: ${{ github.ref }}\n          release_name: Release ${{ github.ref }}\n          #body_path: \".github/RELEASE-TEMPLATE.md\"\n          draft: true\n          files: ${{env.BINARY_NAME}}.zip\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "udpx\n.DS_Store"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 nullt3r@bugdelivery.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![Alt text](screenshots/udpx_logo.png)\n# \nFast and lightweight, UDPX is a single-packet UDP scanner written in Go that supports the discovery of over 45 services with the ability to add custom ones. It is easy to use and portable, and can be run on Linux, Mac OS, and Windows. Unlike internet-wide scanners like zgrab2 and zmap, UDPX is designed for portability and ease of use.\n\n* It is fast. It can scan whole /16 network in ~20 seconds for a single service.\n* You don't need to instal libpcap or any other dependencies.\n* Can run on Linux, Mac Os, Windows. Or your Nethunter if you built it for Arm.\n* Customizable. You can add your probes and test for even more protocols.\n* Stores results in JSONL format.\n* Scans also domain names.\n\n## How it works\nScanning UDP ports is very different than scanning TCP - you may, or may not get any result back from probing an UDP port as UDP is a connectionless protocol. UDPX implements a single-packet based approach. A protocol-specific packet is sent to the defined service (port) and waits for a response. The limit is set to 500 ms by default and can be changed by `-w` flag. If the service sends a packet back within this time, it is certain that it is indeed listening on that port and is reported as open.\n\nA typical technique is to send 0 byte UDP packets to each port on the target machine. If we receive an \"ICMP Port Unreachable\" message, then the port is closed. If an UDP response is received to the probe (unusual), the port is open. If we get no response at all, the state is open or filtered, meaning that the port is either open or packet filters are blocking the communication. This method is not implemented as there is no added value (UDPX tests only for specific protocols).\n\n## Usage\n\n![Alt text](screenshots/showcase.png)\n\n\n> :warning: **Concurrency:** By default, concurrency is set to 32 connections only (so you don't crash anything). If you have a lot of hosts to scan, you can set it to 128 or 256 connections. Based on your hardware, connection stability, and ulimit (on *nix), you can run 512 or more concurrent connections, but this is not recommended.\n\nTo scan a single IP:\n```\nudpx -t 1.1.1.1\n```\n\nTo scan a CIDR with maximum of 128 connections and timeout of 1000 ms:\n```\nudpx -t 1.2.3.4/24 -c 128 -w 1000\n```\n\nTo scan targets from file with maximum of 128 connections for only specific service:\n```\nudpx -tf targets.txt -c 128 -s ipmi\n```\n\nTarget can be:\n* IP address\n* CIDR\n* Domain\n\nIPv6 is supported.\n\nIf you want to store the results, use flag `-o [filename]`. Output is in JSONL format, as can be seen bellow:\n\n```jsonl\n{\"address\":\"45.33.32.156\",\"hostname\":\"scanme.nmap.org\",\"port\":123,\"service\":\"ntp\",\"response_data\":\"JAME6QAAAEoAAA56LU9vp+d2ZPwOYIyDxU8jS3GxUvM=\"}\n```\n\n## Options\n```\n\n        __  ______  ____ _  __\n       / / / / __ \\/ __ \\ |/ /\n      / / / / / / / /_/ /   /\n     / /_/ / /_/ / ____/   |\n     \\____/_____/_/   /_/|_|\n         v1.0.2-beta, by @nullt3r\n\nUsage of ./udpx-linux-amd64:\n  -c int\n    \tMaximum number of concurrent connections (default 32)\n  -nr\n    \tDo not randomize addresses\n  -o string\n    \tOutput file to write results\n  -s string\n    \tScan only for a specific service, one of: ard, bacnet, bacnet_rpm, chargen, citrix, coap, db, db, digi1, digi2, digi3, dns, ipmi, ldap, mdns, memcache, mssql, nat_port_mapping, natpmp, netbios, netis, ntp, ntp_monlist, openvpn, pca_nq, pca_st, pcanywhere, portmap, qotd, rdp, ripv, sentinel, sip, snmp1, snmp2, snmp3, ssdp, tftp, ubiquiti, ubiquiti_discovery_v1, ubiquiti_discovery_v2, upnp, valve, wdbrpc, wsd, wsd_malformed, xdmcp, kerberos, ike\n  -sp\n    \tShow received packets (only first 32 bytes)\n  -t string\n    \tIP/CIDR to scan\n  -tf string\n    \tFile containing IPs/CIDRs to scan\n  -w int\n    \tMaximum time to wait for a response (socket timeout) in ms (default 500)\n```\n\n## Building\nYou can grab prebuilt binaries in the release section. If you want to build UDPX from source, follow these steps:\n\nFrom git:\n```\ngit clone https://github.com/nullt3r/udpx\ncd udpx\ngo build ./cmd/udpx\n```\nYou can find the binary in the current directory.\n\nOr via go:\n```\ngo install -v github.com/nullt3r/udpx/cmd/udpx@latest\n```\n\nAfter that, you can find the binary in `$HOME/go/bin/udpx`. If you want, move binary to `/usr/local/bin/` so you can call it directly.\n\n## Supported services\nThe UDPX supports more then 45 services. The most interesting are:\n* ipmi\n* snmp\n* ike\n* tftp\n* openvpn\n* kerberos\n* ldap\n\nThe complete list of supported services:\n* ard\n* bacnet\n* bacnet_rpm\n* chargen\n* citrix\n* coap\n* db\n* db\n* digi1\n* digi2\n* digi3\n* dns\n* ipmi\n* ldap\n* mdns\n* memcache\n* mssql\n* nat_port_mapping\n* natpmp\n* netbios\n* netis\n* ntp\n* ntp_monlist\n* openvpn\n* pca_nq\n* pca_st\n* pcanywhere\n* portmap\n* qotd\n* rdp\n* ripv\n* sentinel\n* sip\n* snmp1\n* snmp2\n* snmp3\n* ssdp\n* tftp\n* ubiquiti\n* ubiquiti_discovery_v1\n* ubiquiti_discovery_v2\n* upnp\n* valve\n* wdbrpc\n* wsd\n* wsd_malformed\n* xdmcp\n* kerberos\n* ike\n\n## How to add your own probe?\nPlease send a feature request with protocol name and port and I will make it happen. Or add it on your own, the file `pkg/probes/probes.go` contains all available payloads. Specify the protocol name, port and packet data (hex-encoded).\n\n```go\n{\n        Name: \"ike\",\n        Payloads: []string{\"5b5e64c03e99b51100000000000000000110020000000000000001500000013400000001000000010000012801010008030000240101\"},\n        Port: []int{500, 4500},\n},\n```\n\n## Credits\n* [Nmap](https://nmap.org/)\n* [UDP Hunter](https://github.com/NotSoSecure/udp-hunter)\n* [ZGrab2](https://github.com/zmap/zgrab2)\n* [ZMap](https://github.com/zmap/zmap)\n\n## Disclaimer\nI am not responsible for any damages. You are responsible for your own actions. Scanning or attacking targets without prior mutual consent can be illegal.\n\n## License\nUDPX is distributed under [MIT License](https://raw.githubusercontent.com/nullt3r/udpx/main/LICENSE).\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/nullt3r/udpx\n\ngo 1.17\n"
  },
  {
    "path": "pkg/colors/color_output.go",
    "content": "package colors\n\nimport \"runtime\"\n\ntype colors struct {\n\tCyan   string\n\tYellow string\n\tRed    string\n\tReset  string\n}\n\nfunc SetColor() *colors {\n\tc := &colors{}\n\n\tif runtime.GOOS == \"windows\" {\n\t\tc.Cyan = \"\"\n\t\tc.Yellow = \"\"\n\t\tc.Red = \"\"\n\t\tc.Reset = \"\"\n\t} else {\n\t\tc.Cyan = \"\\033[36m\"\n\t\tc.Yellow = \"\\033[33m\"\n\t\tc.Red = \"\\033[1;31m\"\n\t\tc.Reset = \"\\033[0m\"\n\t}\n\n\treturn c\n\n}\n"
  },
  {
    "path": "pkg/probes/print_probes.go",
    "content": "package probes\n\nfunc GetProbeNames() string {\n\tvar avail_probes string\n\n\tfor i := range Probes {\n\t\tavail_probes += Probes[i].Name\n\t\tif i != len(Probes)-1 {\n\t\t\tavail_probes += \", \"\n\t\t}\n\t}\n\n\treturn avail_probes\n}\n"
  },
  {
    "path": "pkg/probes/probes.go",
    "content": "package probes\n\ntype Probe struct {\n\tName string\n\tPayloads []string\n\tPort []int\n}\n\nvar Probes = []Probe{\n\t{\n\t\tName: \"ard\",\n\t\tPayloads: []string{\"0014000103\"},\n\t\tPort: []int{3283},\n\t},\n\t{\n\t\tName: \"bacnet\",\n\t\tPayloads: []string{\"810A001101040005D60C0C023FFFFF194B4C\", \"810A002501040205010E0C020000001E090C091C092C09380939093A0946094D097809791F\"},\n\t\tPort: []int{47808},\n\t},\n\t{\n\t\tName: \"chargen\",\n\t\tPayloads: []string{\"01\"},\n\t\tPort: []int{19},\n\t},\n\t{\n\t\tName: \"citrix\",\n\t\tPayloads: []string{\"1E00013002FDA8E300000000000000000000000000000000000000000000\"},\n\t\tPort: []int{1604},\n\t},\n\t{\n\t\tName: \"coap\",\n\t\tPayloads: []string{\"40017D70BB2E77656C6C2D6B6E6F776E04636F7265\"},\n\t\tPort: []int{5683},\n\t},\n\t{\n\t\tName: \"db\",\n\t\tPayloads: []string{\"444232474554414444520053514C303930313000\", \"444232474554414444520053514C303530303000\"},\n\t\tPort: []int{523},\n\t},\n\t{\n\t\tName: \"digi\",\n\t\tPayloads: []string{\"4449474900010006FFFFFFFFFFFF\", \"44564B5400010006FFFFFFFFFFFF\", \"4447445000010006FFFFFFFFFFFF\"},\n\t\tPort: []int{2362},\n\t},\n\t{\n\t\tName: \"dns\",\n\t\tPayloads: []string{\"34EF010000010000000000000756455253494F4E0442494E440000100003\", \"AE0D010000010000000000000377777706676F6F676C6503636F6D0000010001\"},\n\t\tPort: []int{53},\n\t},\n\t{\n\t\tName: \"ipmi\",\n\t\tPayloads: []string{\"0600FF07000000000000000000092018C88100388E04B5\"},\n\t\tPort: []int{623},\n\t},\n\t{\n\t\tName: \"ldap\",\n\t\tPayloads: []string{\"30840000002D02010163840000002404000A01000A0100020100020100010100870B6F626A656374636C617373308400000000000A\"},\n\t\tPort: []int{389},\n\t},\n\t{\n\t\tName: \"mdns\",\n\t\tPayloads: []string{\"000000000001000000000000095F7365727669636573075F646E732D7364045F756470056C6F63616C00000C0001\"},\n\t\tPort: []int{5353},\n\t},\n\t{\n\t\tName: \"memcache\",\n\t\tPayloads: []string{\"5A4D0000000100007374617473206974656D730D0A\"},\n\t\tPort: []int{11211},\n\t},\n\t{\n\t\tName: \"mssql\",\n\t\tPayloads: []string{\"02\"},\n\t\tPort: []int{1434},\n\t},\n\t{\n\t\tName: \"nat\",\n\t\tPayloads: []string{\"0000000000000000000000000000E3B3E483\", \"00000000\"},\n\t\tPort: []int{5351},\n\t},\n\t{\n\t\tName: \"netbios\",\n\t\tPayloads: []string{\"E5D80000000100000000000020434B4141414141414141414141414141414141414141414141414141414141410000210001\"},\n\t\tPort: []int{137},\n\t},\n\t{\n\t\tName: \"netis\",\n\t\tPayloads: []string{\"0A000000000000000000000000009E21BDAD\"},\n\t\tPort: []int{53413},\n\t},\n\t{\n\t\tName: \"ntp\",\n\t\tPayloads: []string{\"E30004FA000100000001000000000000000000000000000000000000000000000000000000000000C54F234B71B152F3\", \"1700032A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"},\n\t\tPort: []int{123},\n\t},\n\t{\n\t\tName: \"openvpn\",\n\t\tPayloads: []string{\"381212121212121212000000000038B126DE\"},\n\t\tPort: []int{1194},\n\t},\n\t{\n\t\tName: \"pca\",\n\t\tPayloads: []string{\"4E51\", \"5354\", \"4E5100000000000000000000000041F4BFA6\"},\n\t\tPort: []int{5632},\n\t},\n\t{\n\t\tName: \"portmap\",\n\t\tPayloads: []string{\"1AA9FFE10000000000000002000186A0000000020000000400000000000000000000000000000000\"},\n\t\tPort: []int{111},\n\t},\n\t{\n\t\tName: \"qotd\",\n\t\tPayloads: []string{\"0D0A\"},\n\t\tPort: []int{17},\n\t},\n\t{\n\t\tName: \"rdp\",\n\t\tPayloads: []string{\"00000000000000FF00000000000000005406\"},\n\t\tPort: []int{3389},\n\t},\n\t{\n\t\tName: \"ripv\",\n\t\tPayloads: []string{\"010100000000000000000000000000000000000000001000\"},\n\t\tPort: []int{520},\n\t},\n\t{\n\t\tName: \"sentinel\",\n\t\tPayloads: []string{\"7A0000000000\"},\n\t\tPort: []int{5093},\n\t},\n\t{\n\t\tName: \"sip\",\n\t\tPayloads: []string{\"4F5054494F4E53\"},\n\t\tPort: []int{5060},\n\t},\n\t{\n\t\tName: \"snmp\",\n\t\tPayloads: []string{\"302902010004067075626C6963A01C0204565ADC5D020100020100300E300C06082B060102010101000500\", \"302602010104067075626C6963A1190204DC63C29A020100020100300B300906052B060102010500\", \"303A020103300F02024A69020300FFE30401040201030410300E0400020100020100040004000400301204000400A00C020237F00201000201003000\"},\n\t\tPort: []int{161},\n\t},\n\t{\n\t\tName: \"ssdp\",\n\t\tPayloads: []string{\"4D2D534541524348202A20485454502F312E310D0A484F53543A3233392E3235352E3235352E3235303A313930300D0A53543A737364703A616C6C0D0A4D414E3A22737364703A646973636F766572220D0A0D0A\"},\n\t\tPort: []int{1900},\n\t},\n\t{\n\t\tName: \"tftp\",\n\t\tPayloads: []string{\"00012F61006E6574617363696900\"},\n\t\tPort: []int{69},\n\t},\n\t{\n\t\tName: \"ubiquiti\",\n\t\tPayloads: []string{\"01000000000000000000000000001F7FA366\", \"01000000\", \"02080000\"},\n\t\tPort: []int{10001},\n\t},\n\t{\n\t\tName: \"upnp\",\n\t\tPayloads: []string{\"4D2D534541524348202A20485454502F312E310D0A486F73743A3233392E3235352E3235352E3235303A313930300D0A53543A75706E703A726F6F746465766963650D0A4D616E3A22737364703A646973636F766572220D0A4D583A330D0A0D0A0D0A\"},\n\t\tPort: []int{1900},\n\t},\n\t{\n\t\tName: \"valve\",\n\t\tPayloads: []string{\"FFFFFFFF54536F7572636520456E67696E6520517565727900\"},\n\t\tPort: []int{27015},\n\t},\n\t{\n\t\tName: \"wdbrpc\",\n\t\tPayloads: []string{\"1A09FABA000000000000000255555555000000010000000100000000000000000000000000000000FFFF55120000003C00000001000000020000000000000000\"},\n\t\tPort: []int{17185},\n\t},\n\t{\n\t\tName: \"wsd\",\n\t\tPayloads: []string{\"3C3A2F3E0A\", \"3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D227574662D38223F3E0A3C736F61703A456E76656C6F706520786D6C6E733A736F61703D22687474703A2F2F7777772E77332E6F72672F323030332F30352F736F61702D656E76656C6F70652220786D6C6E733A7773613D22687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030342F30382F61646472657373696E672220786D6C6E733A7773643D22687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030352F30342F646973636F766572792220786D6C6E733A777364703D22687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030362F30322F64657670726F66223E0A3C736F61703A4865616465723E3C7773613A546F3E75726E3A736368656D61732D786D6C736F61702D6F72673A77733A323030353A30343A646973636F766572793C2F7773613A546F3E3C7773613A416374696F6E3E687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030352F30342F646973636F766572792F50726F62653C2F7773613A416374696F6E3E3C7773613A4D65737361676549443E75726E3A757569643A63653034646164302D356432632D343032362D393134362D3161616266633165343131313C2F7773613A4D65737361676549443E3C2F736F61703A4865616465723E3C736F61703A426F64793E3C7773643A50726F62653E3C7773643A54797065733E777364703A4465766963653C2F7773643A54797065733E3C2F7773643A50726F62653E3C2F736F61703A426F64793E3C2F736F61703A456E76656C6F70653E0A\"},\n\t\tPort: []int{3702},\n\t},\n\t{\n\t\tName: \"xdmcp\",\n\t\tPayloads: []string{\"00010002000100\"},\n\t\tPort: []int{177},\n\t},\n\t{\n\t\tName: \"kerberos\",\n\t\tPayloads: []string{\"6A7A3078A103020105A20302010AA46C306AA00703050040000000A111300FA003020101A10830061B046E6D6170A2061B0474657374A3193017A003020102A110300E1B066B72627467741B0474657374A511180F32303232313131333231343530325AA7060204094A7681A80E300C020112020111020110020117\"},\n\t\tPort: []int{88},\n\t},\n\t{\n\t\tName: \"ike\",\n\t\tPayloads: []string{\"5b5e64c03e99b51100000000000000000110020000000000000001500000013400000001000000010000012801010008030000240101\"},\n\t\tPort: []int{500, 4500},\n\t},\n\t{\n\t\tName: \"radius\",\n\t\tPayloads: []string{\"0167005740b664dbf5d681b2adbd1769515118c8010773746576650212dbc6c4b758be14f005b3877c9e2fb6010406c0a8001c05060000007b50125f0f8647e8c89bd881364268fcd045324f0c0266000a017374657665\"},\n\t\tPort: []int{1645, 1812},\n\t},\n\t{\n\t\tName: \"dtls\",\n\t\tPayloads: []string{\"0d31323334353637385139393900\", \"16feff00000000000000000036\", \"0100002a000000000000002a\", \"fefd\", \"0000\", \"0002002f\", \"0100\"},\n\t\tPort: []int{80,443,853,3391,4433,4740,5349,5684,5868,6514,6636,8232,10161,10162,12346,12446,12546,12646,12746,12846,12946,13046},\n\t},\n}\n\n"
  },
  {
    "path": "pkg/scan/scanner.go",
    "content": "package scan\n\nimport (\n\t\"bufio\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/nullt3r/udpx/pkg/colors\"\n\t\"github.com/nullt3r/udpx/pkg/probes\"\n)\n\ntype Scanner struct {\n\tTarget  string\n\tProbes  []probes.Probe\n\tArg_st  int\n\tArg_sp  bool\n\tChannel chan Message\n}\n\ntype Message struct {\n\tAddress      string `json:\"address\"`\n\tHostname     string `json:\"hostname\"`\n\tPort         int    `json:\"port\"`\n\tService      string `json:\"service\"`\n\tResponseData []byte `json:\"response_data\"`\n\tTimestamp    int64  `json:\"timestamp\"`\n}\n\nfunc (s Scanner) Run() {\n\tsocketTimeout := time.Duration(s.Arg_st) * time.Millisecond\n\ttarget := s.Target\n\n\t// Check if input is a domain\n\tif net.ParseIP(target) == nil {\n\t\t// Resolve domain to IP\n\t\tips, err := net.LookupIP(target)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"%s[!]%s Error resolving domain '%s': %s\", colors.SetColor().Red, colors.SetColor().Reset, target, err)\n\t\t\treturn\n\t\t}\n\t\tdomain := target\n\n\t\t// Dial for each IP of domain\n\t\tfor _, ip := range ips {\n\t\t\tip := ip.String()\n\t\t\t// If IP is IPv6\n\t\t\tif strings.Contains(ip, \":\") {\n\t\t\t\tip = \"[\" + ip + \"]\"\n\t\t\t}\n\t\t\tfor _, probe := range probes.Probes {\n\t\t\t\tfor _, port := range probe.Port {\n\t\t\t\t\tfunc() {\n\n\t\t\t\t\t\tfor _, payload := range probe.Payloads {\n\t\t\t\t\t\t\trecv_Data := make([]byte, 32)\n\n\t\t\t\t\t\t\tc, err := net.Dial(\"udp\", fmt.Sprint(ip, \":\", port))\n\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\tlog.Printf(\"%s[!]%s [%s] Error connecting to host '%s': %s\", colors.SetColor().Red, colors.SetColor().Reset, probe.Name, ip, err)\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tdefer c.Close()\n\n\t\t\t\t\t\t\tData, err := hex.DecodeString(payload)\n\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\tlog.Fatalf(\"%s[!]%s Error in decoding payload. Problem probe: '%s'\", colors.SetColor().Red, colors.SetColor().Reset, probe.Name)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_, err = c.Write([]byte(Data))\n\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tc.SetReadDeadline(time.Now().Add(socketTimeout))\n\n\t\t\t\t\t\t\trecv_length, err := bufio.NewReader(c).Read(recv_Data)\n\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif recv_length != 0 {\n\t\t\t\t\t\t\t\ts.Channel <- Message{Address: ip, Hostname: domain, Port: port, Service: probe.Name, ResponseData: recv_Data}\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Dial for a single IP\n\t\tip := target\n\t\t// If IP is IPv6\n\t\tif strings.Contains(ip, \":\") {\n\t\t\tip = \"[\" + ip + \"]\"\n\t\t}\n\t\tfor _, probe := range probes.Probes {\n\t\t\tfor _, port := range probe.Port {\n\t\t\t\tfunc() {\n\t\t\t\t\tfor _, payload := range probe.Payloads {\n\t\t\t\t\t\trecv_Data := make([]byte, 32)\n\n\t\t\t\t\t\tnow := time.Now()\n\n\t\t\t\t\t\tc, err := net.Dial(\"udp\", fmt.Sprint(ip, \":\", port))\n\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tlog.Printf(\"%s[!]%s [%s] Error connecting to host '%s': %s\", colors.SetColor().Red, colors.SetColor().Reset, probe.Name, ip, err)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefer c.Close()\n\n\t\t\t\t\t\tData, err := hex.DecodeString(payload)\n\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tlog.Fatalf(\"%s[!]%s Error in decoding payload. Problem probe: '%s'\", colors.SetColor().Red, colors.SetColor().Reset, probe.Name)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_, err = c.Write([]byte(Data))\n\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tc.SetReadDeadline(time.Now().Add(socketTimeout))\n\n\t\t\t\t\t\trecv_length, err := bufio.NewReader(c).Read(recv_Data)\n\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif recv_length != 0 {\n\t\t\t\t\t\t\ts.Channel <- Message{Address: ip, Port: port, Service: probe.Name, ResponseData: recv_Data, Timestamp: now.Unix()}\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/utils/helpers.go",
    "content": "package utils\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n)\n\nfunc EscapeByteArray(message []byte) []byte {\n    var result []byte\n    for _, b := range message {\n        if b > 127 || b == '\"' || b == '\\n' || b == '\\t' || (b <= ' ' && b >= 0) {\n            result = append(result, []byte(fmt.Sprintf(\"\\\\x%02x\", b))...)\n        } else {\n            result = append(result, b)\n        }\n    }\n    return result\n}\n\nfunc IpsFromCidr(cidr string) ([]string, error) {\n\tinc := func(ip net.IP) {\n\t\tfor j := len(ip) - 1; j >= 0; j-- {\n\t\t\tip[j]++\n\t\t\tif ip[j] > 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tip, ipnet, err := net.ParseCIDR(cidr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar ips []string\n\n\tfor ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {\n\t\tips = append(ips, ip.String())\n\t}\n\n\t// If mask is /32 or /31\n\t//if len(ips) <= 2 {\n\t//\treturn ips, nil\n\t//}\n\n\t// remove network address and broadcast address\n\t//return ips[1 : len(ips)-1], nil\n\n\treturn ips, nil\n}\n\nfunc ReadFile(path string) ([]string, error) {\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer file.Close()\n\n\tvar lines []string\n\tscanner := bufio.NewScanner(file)\n\tfor scanner.Scan() {\n\t\tlines = append(lines, scanner.Text())\n\t}\n\treturn lines, scanner.Err()\n}\n\nfunc WriteChannel(lines chan string, path string) error {\n\tfile, err := os.Create(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\n\tw := bufio.NewWriter(file)\n\tfor line := range lines {\n\t\tfmt.Fprintln(w, line)\n\t}\n\treturn w.Flush()\n}\n\n\nfunc Deduplicate(stringSlice []string) []string {\n\tkeys := make(map[string]bool)\n\tlist := []string{}\n\n\t// If the key(values of the slice) is not equal\n\t// to the already present value in new slice (list)\n\t// then we append it. else we jump on another element.\n\tfor _, entry := range stringSlice {\n\t\tif _, value := keys[entry]; !value {\n\t\t\tkeys[entry] = true\n\t\t\tlist = append(list, entry)\n\t\t}\n\t}\n\treturn list\n}\n"
  },
  {
    "path": "pkg/utils/opts_parser.go",
    "content": "package utils\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\n\t\"github.com/nullt3r/udpx/pkg/probes\"\n)\n\ntype Options struct {\n\tArg_t  string\n\tArg_tf string\n\tArg_o  string\n\tArg_c  int\n\tArg_nr bool\n\tArg_st int\n\tArg_sp bool\n\tArg_s  string\n}\n\nfunc ParseOptions() *Options {\n\topts := &Options{}\n\tflag.StringVar(&opts.Arg_t, \"t\", \"\", \"IP/CIDR to scan\")\n\tflag.StringVar(&opts.Arg_tf, \"tf\", \"\", \"File containing IPs/CIDRs to scan\")\n\tflag.StringVar(&opts.Arg_o, \"o\", \"\", \"Output file to write results\")\n\tflag.StringVar(&opts.Arg_s, \"s\", \"\", fmt.Sprintf(\"Scan only for a specific service, one of: %s\", probes.GetProbeNames()))\n\tflag.IntVar(&opts.Arg_c, \"c\", 32, \"Maximum number of concurrent connections\")\n\tflag.BoolVar(&opts.Arg_nr, \"nr\", false, \"Do not randomize addresses\")\n\tflag.IntVar(&opts.Arg_st, \"w\", 500, \"Maximum time to wait for a response (socket timeout) in ms\")\n\tflag.BoolVar(&opts.Arg_sp, \"sp\", false, \"Show received packets (only first 32 bytes)\")\n\n\tflag.Parse()\n\n\treturn opts\n}\n"
  }
]