package net12import (3"context"4"crypto/tls"5"encoding/hex"6"fmt"7"net"8"time"910"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"11"github.com/projectdiscovery/nuclei/v3/pkg/types"12"github.com/projectdiscovery/utils/errkit"13"github.com/projectdiscovery/utils/reader"14)1516var (17defaultTimeout = time.Duration(5) * time.Second18)1920// Open opens a new connection to the address with a timeout.21// supported protocols: tcp, udp22// @example23// ```javascript24// const net = require('nuclei/net');25// const conn = net.Open('tcp', 'acme.com:80');26// ```27func Open(ctx context.Context, protocol, address string) (*NetConn, error) {28executionId := ctx.Value("executionId").(string)29dialer := protocolstate.GetDialersWithId(executionId)30if dialer == nil {31return nil, fmt.Errorf("dialers not initialized for %s", executionId)32}33conn, err := dialer.Fastdialer.Dial(ctx, protocol, address)34if err != nil {35return nil, err36}37return &NetConn{conn: conn, timeout: defaultTimeout}, nil38}3940// Open opens a new connection to the address with a timeout.41// supported protocols: tcp, udp42// @example43// ```javascript44// const net = require('nuclei/net');45// const conn = net.OpenTLS('tcp', 'acme.com:443');46// ```47func OpenTLS(ctx context.Context, protocol, address string) (*NetConn, error) {48config := &tls.Config{InsecureSkipVerify: true, MinVersion: tls.VersionTLS10}49host, _, _ := net.SplitHostPort(address)50if host != "" {51c := config.Clone()52c.ServerName = host53config = c54}55executionId := ctx.Value("executionId").(string)56dialer := protocolstate.GetDialersWithId(executionId)57if dialer == nil {58return nil, fmt.Errorf("dialers not initialized for %s", executionId)59}6061conn, err := dialer.Fastdialer.DialTLSWithConfig(ctx, protocol, address, config)62if err != nil {63return nil, err64}65return &NetConn{conn: conn, timeout: defaultTimeout}, nil66}6768type (69// NetConn is a connection to a remote host.70// this is returned/create by Open and OpenTLS functions.71// @example72// ```javascript73// const net = require('nuclei/net');74// const conn = net.Open('tcp', 'acme.com:80');75// ```76NetConn struct {77conn net.Conn78timeout time.Duration79}80)8182// Close closes the connection.83// @example84// ```javascript85// const net = require('nuclei/net');86// const conn = net.Open('tcp', 'acme.com:80');87// conn.Close();88// ```89func (c *NetConn) Close() error {90err := c.conn.Close()91return err92}9394// SetTimeout sets read/write timeout for the connection (in seconds).95// @example96// ```javascript97// const net = require('nuclei/net');98// const conn = net.Open('tcp', 'acme.com:80');99// conn.SetTimeout(10);100// ```101func (c *NetConn) SetTimeout(value int) {102c.timeout = time.Duration(value) * time.Second103}104105// setDeadLine sets read/write deadline for the connection (in seconds).106// this is intended to be called before every read/write operation.107func (c *NetConn) setDeadLine() {108if c.timeout == 0 {109c.timeout = 5 * time.Second110}111_ = c.conn.SetDeadline(time.Now().Add(c.timeout))112}113114// unsetDeadLine unsets read/write deadline for the connection.115func (c *NetConn) unsetDeadLine() {116_ = c.conn.SetDeadline(time.Time{})117}118119// SendArray sends array data to connection120// @example121// ```javascript122// const net = require('nuclei/net');123// const conn = net.Open('tcp', 'acme.com:80');124// conn.SendArray(['hello', 'world']);125// ```126func (c *NetConn) SendArray(data []interface{}) error {127c.setDeadLine()128defer c.unsetDeadLine()129input := types.ToByteSlice(data)130length, err := c.conn.Write(input)131if err != nil {132return err133}134if length < len(input) {135return fmt.Errorf("failed to write all bytes (%d bytes written, %d bytes expected)", length, len(input))136}137return nil138}139140// SendHex sends hex data to connection141// @example142// ```javascript143// const net = require('nuclei/net');144// const conn = net.Open('tcp', 'acme.com:80');145// conn.SendHex('68656c6c6f');146// ```147func (c *NetConn) SendHex(data string) error {148c.setDeadLine()149defer c.unsetDeadLine()150bin, err := hex.DecodeString(data)151if err != nil {152return err153}154length, err := c.conn.Write(bin)155if err != nil {156return err157}158if length < len(bin) {159return fmt.Errorf("failed to write all bytes (%d bytes written, %d bytes expected)", length, len(bin))160}161return nil162}163164// Send sends data to the connection with a timeout.165// @example166// ```javascript167// const net = require('nuclei/net');168// const conn = net.Open('tcp', 'acme.com:80');169// conn.Send('hello');170// ```171func (c *NetConn) Send(data string) error {172c.setDeadLine()173defer c.unsetDeadLine()174bin := []byte(data)175length, err := c.conn.Write(bin)176if err != nil {177return err178}179if length < len(bin) {180return fmt.Errorf("failed to write all bytes (%d bytes written, %d bytes expected)", length, len(data))181}182return nil183}184185// RecvFull receives data from the connection with a timeout.186// If N is 0, it will read all data sent by the server with 8MB limit.187// it tries to read until N bytes or timeout is reached.188// @example189// ```javascript190// const net = require('nuclei/net');191// const conn = net.Open('tcp', 'acme.com:80');192// const data = conn.RecvFull(1024);193// ```194func (c *NetConn) RecvFull(N int) ([]byte, error) {195c.setDeadLine()196defer c.unsetDeadLine()197if N == 0 {198// in utils we use -1 to indicate read all rather than 0199N = -1200}201bin, err := reader.ConnReadNWithTimeout(c.conn, int64(N), c.timeout)202if err != nil {203return []byte{}, errkit.Wrapf(err, "failed to read %d bytes", N)204}205return bin, nil206}207208// Recv is similar to RecvFull but does not guarantee full read instead209// it creates a buffer of N bytes and returns whatever is returned by the connection210// for reading headers or initial bytes from the server this is usually used.211// for reading a fixed number of already known bytes (ex: body based on content-length) use RecvFull.212// @example213// ```javascript214// const net = require('nuclei/net');215// const conn = net.Open('tcp', 'acme.com:80');216// const data = conn.Recv(1024);217// log(`Received ${data.length} bytes from the server`)218// ```219func (c *NetConn) Recv(N int) ([]byte, error) {220c.setDeadLine()221defer c.unsetDeadLine()222if N == 0 {223N = 4096224}225b := make([]byte, N)226n, err := c.conn.Read(b)227if err != nil {228return []byte{}, errkit.Wrapf(err, "failed to read %d bytes", N)229}230return b[:n], nil231}232233// RecvFullString receives data from the connection with a timeout234// output is returned as a string.235// If N is 0, it will read all data sent by the server with 8MB limit.236// @example237// ```javascript238// const net = require('nuclei/net');239// const conn = net.Open('tcp', 'acme.com:80');240// const data = conn.RecvFullString(1024);241// ```242func (c *NetConn) RecvFullString(N int) (string, error) {243bin, err := c.RecvFull(N)244if err != nil {245return "", err246}247return string(bin), nil248}249250// RecvString is similar to RecvFullString but does not guarantee full read, instead251// it creates a buffer of N bytes and returns whatever is returned by the connection252// for reading headers or initial bytes from the server this is usually used.253// for reading a fixed number of already known bytes (ex: body based on content-length) use RecvFullString.254// @example255// ```javascript256// const net = require('nuclei/net');257// const conn = net.Open('tcp', 'acme.com:80');258// const data = conn.RecvString(1024);259// ```260func (c *NetConn) RecvString(N int) (string, error) {261bin, err := c.Recv(N)262if err != nil {263return "", err264}265return string(bin), nil266}267268// RecvFullHex receives data from the connection with a timeout269// in hex format.270// If N is 0,it will read all data sent by the server with 8MB limit.271// until N bytes or timeout is reached.272// @example273// ```javascript274// const net = require('nuclei/net');275// const conn = net.Open('tcp', 'acme.com:80');276// const data = conn.RecvFullHex(1024);277// ```278func (c *NetConn) RecvFullHex(N int) (string, error) {279bin, err := c.RecvFull(N)280if err != nil {281return "", err282}283return hex.Dump(bin), nil284}285286// RecvHex is similar to RecvFullHex but does not guarantee full read instead287// it creates a buffer of N bytes and returns whatever is returned by the connection288// for reading headers or initial bytes from the server this is usually used.289// for reading a fixed number of already known bytes (ex: body based on content-length) use RecvFull.290// @example291// ```javascript292// const net = require('nuclei/net');293// const conn = net.Open('tcp', 'acme.com:80');294// const data = conn.RecvHex(1024);295// ```296func (c *NetConn) RecvHex(N int) (string, error) {297bin, err := c.Recv(N)298if err != nil {299return "", err300}301return hex.Dump(bin), nil302}303304305