Full Code of nullt3r/udpx for AI

main 7e6ea01359d6 cached
11 files
22.8 KB
8.2k tokens
14 symbols
1 requests
Download .txt
Repository: nullt3r/udpx
Branch: main
Commit: 7e6ea01359d6
Files: 11
Total size: 22.8 KB

Directory structure:
gitextract_i9srdjvc/

├── .github/
│   └── workflows/
│       └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── go.mod
└── pkg/
    ├── colors/
    │   └── color_output.go
    ├── probes/
    │   ├── print_probes.go
    │   └── probes.go
    ├── scan/
    │   └── scanner.go
    └── utils/
        ├── helpers.go
        └── opts_parser.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/release.yml
================================================
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: Release

on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10

jobs:

  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        goosarch:
          - 'linux/amd64'
          - 'linux/386'
          - 'darwin/amd64'
          - 'darwin/arm64'
          - 'windows/amd64'
          - 'windows/386'
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - uses: actions/setup-go@v2
        with:
          go-version: '1.17'
      - name: Get OS and arch info
        run: |
          GOOSARCH=${{matrix.goosarch}}
          GOOS=${GOOSARCH%/*}
          GOARCH=${GOOSARCH#*/}
          BINARY_NAME=${{github.event.repository.name}}-$GOOS-$GOARCH
          echo "BINARY_NAME=$BINARY_NAME" >> $GITHUB_ENV
          echo "GOOS=$GOOS" >> $GITHUB_ENV
          echo "GOARCH=$GOARCH" >> $GITHUB_ENV
      - name: Build
        run: |
          go build -o "$BINARY_NAME" -v ./cmd/udpx

      - name: Zip bin
        run: zip -r ${{env.BINARY_NAME}}.zip ${{env.BINARY_NAME}}

      #- name: Release Notes
      #  run:
      #    git log $(git describe HEAD~ --tags --abbrev=0)..HEAD --pretty='format:* %h %s%n  * %an <%ae>' --no-merges >> ".github/RELEASE-TEMPLATE.md"
      - name: Release with Notes
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          #body_path: ".github/RELEASE-TEMPLATE.md"
          draft: true
          files: ${{env.BINARY_NAME}}.zip
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
udpx
.DS_Store

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 nullt3r@bugdelivery.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
![Alt text](screenshots/udpx_logo.png)
# 
Fast 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.

* It is fast. It can scan whole /16 network in ~20 seconds for a single service.
* You don't need to instal libpcap or any other dependencies.
* Can run on Linux, Mac Os, Windows. Or your Nethunter if you built it for Arm.
* Customizable. You can add your probes and test for even more protocols.
* Stores results in JSONL format.
* Scans also domain names.

## How it works
Scanning 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.

A 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).

## Usage

![Alt text](screenshots/showcase.png)


> :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.

To scan a single IP:
```
udpx -t 1.1.1.1
```

To scan a CIDR with maximum of 128 connections and timeout of 1000 ms:
```
udpx -t 1.2.3.4/24 -c 128 -w 1000
```

To scan targets from file with maximum of 128 connections for only specific service:
```
udpx -tf targets.txt -c 128 -s ipmi
```

Target can be:
* IP address
* CIDR
* Domain

IPv6 is supported.

If you want to store the results, use flag `-o [filename]`. Output is in JSONL format, as can be seen bellow:

```jsonl
{"address":"45.33.32.156","hostname":"scanme.nmap.org","port":123,"service":"ntp","response_data":"JAME6QAAAEoAAA56LU9vp+d2ZPwOYIyDxU8jS3GxUvM="}
```

## Options
```

        __  ______  ____ _  __
       / / / / __ \/ __ \ |/ /
      / / / / / / / /_/ /   /
     / /_/ / /_/ / ____/   |
     \____/_____/_/   /_/|_|
         v1.0.2-beta, by @nullt3r

Usage of ./udpx-linux-amd64:
  -c int
    	Maximum number of concurrent connections (default 32)
  -nr
    	Do not randomize addresses
  -o string
    	Output file to write results
  -s string
    	Scan 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
  -sp
    	Show received packets (only first 32 bytes)
  -t string
    	IP/CIDR to scan
  -tf string
    	File containing IPs/CIDRs to scan
  -w int
    	Maximum time to wait for a response (socket timeout) in ms (default 500)
```

## Building
You can grab prebuilt binaries in the release section. If you want to build UDPX from source, follow these steps:

From git:
```
git clone https://github.com/nullt3r/udpx
cd udpx
go build ./cmd/udpx
```
You can find the binary in the current directory.

Or via go:
```
go install -v github.com/nullt3r/udpx/cmd/udpx@latest
```

After 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.

## Supported services
The UDPX supports more then 45 services. The most interesting are:
* ipmi
* snmp
* ike
* tftp
* openvpn
* kerberos
* ldap

The complete list of supported services:
* 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

## How to add your own probe?
Please 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).

```go
{
        Name: "ike",
        Payloads: []string{"5b5e64c03e99b51100000000000000000110020000000000000001500000013400000001000000010000012801010008030000240101"},
        Port: []int{500, 4500},
},
```

## Credits
* [Nmap](https://nmap.org/)
* [UDP Hunter](https://github.com/NotSoSecure/udp-hunter)
* [ZGrab2](https://github.com/zmap/zgrab2)
* [ZMap](https://github.com/zmap/zmap)

## Disclaimer
I am not responsible for any damages. You are responsible for your own actions. Scanning or attacking targets without prior mutual consent can be illegal.

## License
UDPX is distributed under [MIT License](https://raw.githubusercontent.com/nullt3r/udpx/main/LICENSE).


================================================
FILE: go.mod
================================================
module github.com/nullt3r/udpx

go 1.17


================================================
FILE: pkg/colors/color_output.go
================================================
package colors

import "runtime"

type colors struct {
	Cyan   string
	Yellow string
	Red    string
	Reset  string
}

func SetColor() *colors {
	c := &colors{}

	if runtime.GOOS == "windows" {
		c.Cyan = ""
		c.Yellow = ""
		c.Red = ""
		c.Reset = ""
	} else {
		c.Cyan = "\033[36m"
		c.Yellow = "\033[33m"
		c.Red = "\033[1;31m"
		c.Reset = "\033[0m"
	}

	return c

}


================================================
FILE: pkg/probes/print_probes.go
================================================
package probes

func GetProbeNames() string {
	var avail_probes string

	for i := range Probes {
		avail_probes += Probes[i].Name
		if i != len(Probes)-1 {
			avail_probes += ", "
		}
	}

	return avail_probes
}


================================================
FILE: pkg/probes/probes.go
================================================
package probes

type Probe struct {
	Name string
	Payloads []string
	Port []int
}

var Probes = []Probe{
	{
		Name: "ard",
		Payloads: []string{"0014000103"},
		Port: []int{3283},
	},
	{
		Name: "bacnet",
		Payloads: []string{"810A001101040005D60C0C023FFFFF194B4C", "810A002501040205010E0C020000001E090C091C092C09380939093A0946094D097809791F"},
		Port: []int{47808},
	},
	{
		Name: "chargen",
		Payloads: []string{"01"},
		Port: []int{19},
	},
	{
		Name: "citrix",
		Payloads: []string{"1E00013002FDA8E300000000000000000000000000000000000000000000"},
		Port: []int{1604},
	},
	{
		Name: "coap",
		Payloads: []string{"40017D70BB2E77656C6C2D6B6E6F776E04636F7265"},
		Port: []int{5683},
	},
	{
		Name: "db",
		Payloads: []string{"444232474554414444520053514C303930313000", "444232474554414444520053514C303530303000"},
		Port: []int{523},
	},
	{
		Name: "digi",
		Payloads: []string{"4449474900010006FFFFFFFFFFFF", "44564B5400010006FFFFFFFFFFFF", "4447445000010006FFFFFFFFFFFF"},
		Port: []int{2362},
	},
	{
		Name: "dns",
		Payloads: []string{"34EF010000010000000000000756455253494F4E0442494E440000100003", "AE0D010000010000000000000377777706676F6F676C6503636F6D0000010001"},
		Port: []int{53},
	},
	{
		Name: "ipmi",
		Payloads: []string{"0600FF07000000000000000000092018C88100388E04B5"},
		Port: []int{623},
	},
	{
		Name: "ldap",
		Payloads: []string{"30840000002D02010163840000002404000A01000A0100020100020100010100870B6F626A656374636C617373308400000000000A"},
		Port: []int{389},
	},
	{
		Name: "mdns",
		Payloads: []string{"000000000001000000000000095F7365727669636573075F646E732D7364045F756470056C6F63616C00000C0001"},
		Port: []int{5353},
	},
	{
		Name: "memcache",
		Payloads: []string{"5A4D0000000100007374617473206974656D730D0A"},
		Port: []int{11211},
	},
	{
		Name: "mssql",
		Payloads: []string{"02"},
		Port: []int{1434},
	},
	{
		Name: "nat",
		Payloads: []string{"0000000000000000000000000000E3B3E483", "00000000"},
		Port: []int{5351},
	},
	{
		Name: "netbios",
		Payloads: []string{"E5D80000000100000000000020434B4141414141414141414141414141414141414141414141414141414141410000210001"},
		Port: []int{137},
	},
	{
		Name: "netis",
		Payloads: []string{"0A000000000000000000000000009E21BDAD"},
		Port: []int{53413},
	},
	{
		Name: "ntp",
		Payloads: []string{"E30004FA000100000001000000000000000000000000000000000000000000000000000000000000C54F234B71B152F3", "1700032A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		Port: []int{123},
	},
	{
		Name: "openvpn",
		Payloads: []string{"381212121212121212000000000038B126DE"},
		Port: []int{1194},
	},
	{
		Name: "pca",
		Payloads: []string{"4E51", "5354", "4E5100000000000000000000000041F4BFA6"},
		Port: []int{5632},
	},
	{
		Name: "portmap",
		Payloads: []string{"1AA9FFE10000000000000002000186A0000000020000000400000000000000000000000000000000"},
		Port: []int{111},
	},
	{
		Name: "qotd",
		Payloads: []string{"0D0A"},
		Port: []int{17},
	},
	{
		Name: "rdp",
		Payloads: []string{"00000000000000FF00000000000000005406"},
		Port: []int{3389},
	},
	{
		Name: "ripv",
		Payloads: []string{"010100000000000000000000000000000000000000001000"},
		Port: []int{520},
	},
	{
		Name: "sentinel",
		Payloads: []string{"7A0000000000"},
		Port: []int{5093},
	},
	{
		Name: "sip",
		Payloads: []string{"4F5054494F4E53"},
		Port: []int{5060},
	},
	{
		Name: "snmp",
		Payloads: []string{"302902010004067075626C6963A01C0204565ADC5D020100020100300E300C06082B060102010101000500", "302602010104067075626C6963A1190204DC63C29A020100020100300B300906052B060102010500", "303A020103300F02024A69020300FFE30401040201030410300E0400020100020100040004000400301204000400A00C020237F00201000201003000"},
		Port: []int{161},
	},
	{
		Name: "ssdp",
		Payloads: []string{"4D2D534541524348202A20485454502F312E310D0A484F53543A3233392E3235352E3235352E3235303A313930300D0A53543A737364703A616C6C0D0A4D414E3A22737364703A646973636F766572220D0A0D0A"},
		Port: []int{1900},
	},
	{
		Name: "tftp",
		Payloads: []string{"00012F61006E6574617363696900"},
		Port: []int{69},
	},
	{
		Name: "ubiquiti",
		Payloads: []string{"01000000000000000000000000001F7FA366", "01000000", "02080000"},
		Port: []int{10001},
	},
	{
		Name: "upnp",
		Payloads: []string{"4D2D534541524348202A20485454502F312E310D0A486F73743A3233392E3235352E3235352E3235303A313930300D0A53543A75706E703A726F6F746465766963650D0A4D616E3A22737364703A646973636F766572220D0A4D583A330D0A0D0A0D0A"},
		Port: []int{1900},
	},
	{
		Name: "valve",
		Payloads: []string{"FFFFFFFF54536F7572636520456E67696E6520517565727900"},
		Port: []int{27015},
	},
	{
		Name: "wdbrpc",
		Payloads: []string{"1A09FABA000000000000000255555555000000010000000100000000000000000000000000000000FFFF55120000003C00000001000000020000000000000000"},
		Port: []int{17185},
	},
	{
		Name: "wsd",
		Payloads: []string{"3C3A2F3E0A", "3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D227574662D38223F3E0A3C736F61703A456E76656C6F706520786D6C6E733A736F61703D22687474703A2F2F7777772E77332E6F72672F323030332F30352F736F61702D656E76656C6F70652220786D6C6E733A7773613D22687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030342F30382F61646472657373696E672220786D6C6E733A7773643D22687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030352F30342F646973636F766572792220786D6C6E733A777364703D22687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030362F30322F64657670726F66223E0A3C736F61703A4865616465723E3C7773613A546F3E75726E3A736368656D61732D786D6C736F61702D6F72673A77733A323030353A30343A646973636F766572793C2F7773613A546F3E3C7773613A416374696F6E3E687474703A2F2F736368656D61732E786D6C736F61702E6F72672F77732F323030352F30342F646973636F766572792F50726F62653C2F7773613A416374696F6E3E3C7773613A4D65737361676549443E75726E3A757569643A63653034646164302D356432632D343032362D393134362D3161616266633165343131313C2F7773613A4D65737361676549443E3C2F736F61703A4865616465723E3C736F61703A426F64793E3C7773643A50726F62653E3C7773643A54797065733E777364703A4465766963653C2F7773643A54797065733E3C2F7773643A50726F62653E3C2F736F61703A426F64793E3C2F736F61703A456E76656C6F70653E0A"},
		Port: []int{3702},
	},
	{
		Name: "xdmcp",
		Payloads: []string{"00010002000100"},
		Port: []int{177},
	},
	{
		Name: "kerberos",
		Payloads: []string{"6A7A3078A103020105A20302010AA46C306AA00703050040000000A111300FA003020101A10830061B046E6D6170A2061B0474657374A3193017A003020102A110300E1B066B72627467741B0474657374A511180F32303232313131333231343530325AA7060204094A7681A80E300C020112020111020110020117"},
		Port: []int{88},
	},
	{
		Name: "ike",
		Payloads: []string{"5b5e64c03e99b51100000000000000000110020000000000000001500000013400000001000000010000012801010008030000240101"},
		Port: []int{500, 4500},
	},
	{
		Name: "radius",
		Payloads: []string{"0167005740b664dbf5d681b2adbd1769515118c8010773746576650212dbc6c4b758be14f005b3877c9e2fb6010406c0a8001c05060000007b50125f0f8647e8c89bd881364268fcd045324f0c0266000a017374657665"},
		Port: []int{1645, 1812},
	},
	{
		Name: "dtls",
		Payloads: []string{"0d31323334353637385139393900", "16feff00000000000000000036", "0100002a000000000000002a", "fefd", "0000", "0002002f", "0100"},
		Port: []int{80,443,853,3391,4433,4740,5349,5684,5868,6514,6636,8232,10161,10162,12346,12446,12546,12646,12746,12846,12946,13046},
	},
}



================================================
FILE: pkg/scan/scanner.go
================================================
package scan

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"strings"
	"time"

	"github.com/nullt3r/udpx/pkg/colors"
	"github.com/nullt3r/udpx/pkg/probes"
)

type Scanner struct {
	Target  string
	Probes  []probes.Probe
	Arg_st  int
	Arg_sp  bool
	Channel chan Message
}

type Message struct {
	Address      string `json:"address"`
	Hostname     string `json:"hostname"`
	Port         int    `json:"port"`
	Service      string `json:"service"`
	ResponseData []byte `json:"response_data"`
	Timestamp    int64  `json:"timestamp"`
}

func (s Scanner) Run() {
	socketTimeout := time.Duration(s.Arg_st) * time.Millisecond
	target := s.Target

	// Check if input is a domain
	if net.ParseIP(target) == nil {
		// Resolve domain to IP
		ips, err := net.LookupIP(target)
		if err != nil {
			log.Printf("%s[!]%s Error resolving domain '%s': %s", colors.SetColor().Red, colors.SetColor().Reset, target, err)
			return
		}
		domain := target

		// Dial for each IP of domain
		for _, ip := range ips {
			ip := ip.String()
			// If IP is IPv6
			if strings.Contains(ip, ":") {
				ip = "[" + ip + "]"
			}
			for _, probe := range probes.Probes {
				for _, port := range probe.Port {
					func() {

						for _, payload := range probe.Payloads {
							recv_Data := make([]byte, 32)

							c, err := net.Dial("udp", fmt.Sprint(ip, ":", port))

							if err != nil {
								log.Printf("%s[!]%s [%s] Error connecting to host '%s': %s", colors.SetColor().Red, colors.SetColor().Reset, probe.Name, ip, err)
								return
							}

							defer c.Close()

							Data, err := hex.DecodeString(payload)

							if err != nil {
								log.Fatalf("%s[!]%s Error in decoding payload. Problem probe: '%s'", colors.SetColor().Red, colors.SetColor().Reset, probe.Name)
							}

							_, err = c.Write([]byte(Data))

							if err != nil {
								return
							}

							c.SetReadDeadline(time.Now().Add(socketTimeout))

							recv_length, err := bufio.NewReader(c).Read(recv_Data)

							if err != nil {
								return
							}

							if recv_length != 0 {
								s.Channel <- Message{Address: ip, Hostname: domain, Port: port, Service: probe.Name, ResponseData: recv_Data}
								return
							}
						}
					}()
				}
			}
		}
	} else {
		// Dial for a single IP
		ip := target
		// If IP is IPv6
		if strings.Contains(ip, ":") {
			ip = "[" + ip + "]"
		}
		for _, probe := range probes.Probes {
			for _, port := range probe.Port {
				func() {
					for _, payload := range probe.Payloads {
						recv_Data := make([]byte, 32)

						now := time.Now()

						c, err := net.Dial("udp", fmt.Sprint(ip, ":", port))

						if err != nil {
							log.Printf("%s[!]%s [%s] Error connecting to host '%s': %s", colors.SetColor().Red, colors.SetColor().Reset, probe.Name, ip, err)
							return
						}

						defer c.Close()

						Data, err := hex.DecodeString(payload)

						if err != nil {
							log.Fatalf("%s[!]%s Error in decoding payload. Problem probe: '%s'", colors.SetColor().Red, colors.SetColor().Reset, probe.Name)
						}

						_, err = c.Write([]byte(Data))

						if err != nil {
							return
						}

						c.SetReadDeadline(time.Now().Add(socketTimeout))

						recv_length, err := bufio.NewReader(c).Read(recv_Data)

						if err != nil {
							return
						}

						if recv_length != 0 {
							s.Channel <- Message{Address: ip, Port: port, Service: probe.Name, ResponseData: recv_Data, Timestamp: now.Unix()}
							return
						}
					}
				}()
			}
		}
	}
}


================================================
FILE: pkg/utils/helpers.go
================================================
package utils

import (
	"bufio"
	"fmt"
	"net"
	"os"
)

func EscapeByteArray(message []byte) []byte {
    var result []byte
    for _, b := range message {
        if b > 127 || b == '"' || b == '\n' || b == '\t' || (b <= ' ' && b >= 0) {
            result = append(result, []byte(fmt.Sprintf("\\x%02x", b))...)
        } else {
            result = append(result, b)
        }
    }
    return result
}

func IpsFromCidr(cidr string) ([]string, error) {
	inc := func(ip net.IP) {
		for j := len(ip) - 1; j >= 0; j-- {
			ip[j]++
			if ip[j] > 0 {
				break
			}
		}
	}

	ip, ipnet, err := net.ParseCIDR(cidr)
	if err != nil {
		return nil, err
	}

	var ips []string

	for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
		ips = append(ips, ip.String())
	}

	// If mask is /32 or /31
	//if len(ips) <= 2 {
	//	return ips, nil
	//}

	// remove network address and broadcast address
	//return ips[1 : len(ips)-1], nil

	return ips, nil
}

func ReadFile(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

func WriteChannel(lines chan string, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()

	w := bufio.NewWriter(file)
	for line := range lines {
		fmt.Fprintln(w, line)
	}
	return w.Flush()
}


func Deduplicate(stringSlice []string) []string {
	keys := make(map[string]bool)
	list := []string{}

	// If the key(values of the slice) is not equal
	// to the already present value in new slice (list)
	// then we append it. else we jump on another element.
	for _, entry := range stringSlice {
		if _, value := keys[entry]; !value {
			keys[entry] = true
			list = append(list, entry)
		}
	}
	return list
}


================================================
FILE: pkg/utils/opts_parser.go
================================================
package utils

import (
	"flag"
	"fmt"

	"github.com/nullt3r/udpx/pkg/probes"
)

type Options struct {
	Arg_t  string
	Arg_tf string
	Arg_o  string
	Arg_c  int
	Arg_nr bool
	Arg_st int
	Arg_sp bool
	Arg_s  string
}

func ParseOptions() *Options {
	opts := &Options{}
	flag.StringVar(&opts.Arg_t, "t", "", "IP/CIDR to scan")
	flag.StringVar(&opts.Arg_tf, "tf", "", "File containing IPs/CIDRs to scan")
	flag.StringVar(&opts.Arg_o, "o", "", "Output file to write results")
	flag.StringVar(&opts.Arg_s, "s", "", fmt.Sprintf("Scan only for a specific service, one of: %s", probes.GetProbeNames()))
	flag.IntVar(&opts.Arg_c, "c", 32, "Maximum number of concurrent connections")
	flag.BoolVar(&opts.Arg_nr, "nr", false, "Do not randomize addresses")
	flag.IntVar(&opts.Arg_st, "w", 500, "Maximum time to wait for a response (socket timeout) in ms")
	flag.BoolVar(&opts.Arg_sp, "sp", false, "Show received packets (only first 32 bytes)")

	flag.Parse()

	return opts
}
Download .txt
gitextract_i9srdjvc/

├── .github/
│   └── workflows/
│       └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── go.mod
└── pkg/
    ├── colors/
    │   └── color_output.go
    ├── probes/
    │   ├── print_probes.go
    │   └── probes.go
    ├── scan/
    │   └── scanner.go
    └── utils/
        ├── helpers.go
        └── opts_parser.go
Download .txt
SYMBOL INDEX (14 symbols across 6 files)

FILE: pkg/colors/color_output.go
  type colors (line 5) | type colors struct
  function SetColor (line 12) | func SetColor() *colors {

FILE: pkg/probes/print_probes.go
  function GetProbeNames (line 3) | func GetProbeNames() string {

FILE: pkg/probes/probes.go
  type Probe (line 3) | type Probe struct

FILE: pkg/scan/scanner.go
  type Scanner (line 16) | type Scanner struct
    method Run (line 33) | func (s Scanner) Run() {
  type Message (line 24) | type Message struct

FILE: pkg/utils/helpers.go
  function EscapeByteArray (line 10) | func EscapeByteArray(message []byte) []byte {
  function IpsFromCidr (line 22) | func IpsFromCidr(cidr string) ([]string, error) {
  function ReadFile (line 54) | func ReadFile(path string) ([]string, error) {
  function WriteChannel (line 69) | func WriteChannel(lines chan string, path string) error {
  function Deduplicate (line 84) | func Deduplicate(stringSlice []string) []string {

FILE: pkg/utils/opts_parser.go
  type Options (line 10) | type Options struct
  function ParseOptions (line 21) | func ParseOptions() *Options {
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (26K chars).
[
  {
    "path": ".github/workflows/release.yml",
    "chars": 1851,
    "preview": "# This workflow will build a golang project\n# For more information see: https://docs.github.com/en/actions/automating-bu"
  },
  {
    "path": ".gitignore",
    "chars": 14,
    "preview": "udpx\n.DS_Store"
  },
  {
    "path": "LICENSE",
    "chars": 1080,
    "preview": "MIT License\n\nCopyright (c) 2022 nullt3r@bugdelivery.com\n\nPermission is hereby granted, free of charge, to any person obt"
  },
  {
    "path": "README.md",
    "chars": 5892,
    "preview": "![Alt text](screenshots/udpx_logo.png)\n# \nFast and lightweight, UDPX is a single-packet UDP scanner written in Go that s"
  },
  {
    "path": "go.mod",
    "chars": 40,
    "preview": "module github.com/nullt3r/udpx\n\ngo 1.17\n"
  },
  {
    "path": "pkg/colors/color_output.go",
    "chars": 369,
    "preview": "package colors\n\nimport \"runtime\"\n\ntype colors struct {\n\tCyan   string\n\tYellow string\n\tRed    string\n\tReset  string\n}\n\nfu"
  },
  {
    "path": "pkg/probes/print_probes.go",
    "chars": 211,
    "preview": "package probes\n\nfunc GetProbeNames() string {\n\tvar avail_probes string\n\n\tfor i := range Probes {\n\t\tavail_probes += Probe"
  },
  {
    "path": "pkg/probes/probes.go",
    "chars": 7536,
    "preview": "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"
  },
  {
    "path": "pkg/scan/scanner.go",
    "chars": 3484,
    "preview": "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/c"
  },
  {
    "path": "pkg/utils/helpers.go",
    "chars": 1889,
    "preview": "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 []b"
  },
  {
    "path": "pkg/utils/opts_parser.go",
    "chars": 962,
    "preview": "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\tA"
  }
]

About this extraction

This page contains the full source code of the nullt3r/udpx GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (22.8 KB), approximately 8.2k tokens, and a symbol index with 14 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!