636f7374 / carton.cr

⛵️ Available - Crystal HTTP Proxy Client and Server
BSD 3-Clause Clear License
9 stars 1 forks source link
client connect crystal crystal-shard http http-proxy https mitm proxy server

Carton.cr - HTTP Proxy Client with Server

Description

Features

Usage

require "carton"

# Durian

servers = [] of Durian::Resolver::Server
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("8.8.8.8", 53_i32), protocol: Durian::Protocol::UDP
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("1.1.1.1", 53_i32), protocol: Durian::Protocol::UDP

resolver = Durian::Resolver.new servers
resolver.ip_cache = Durian::Cache::IPAddress.new

# Carton

begin

  client = Carton::Client.new "0.0.0.0", 1234_i32, resolver

  # Authentication (Optional)
  # client.authentication = Carton::Authentication::Basic
  # client.on_auth = Carton::AuthenticationEntry.new "admin", "abc123"

  # Handshake

  client.connect! "www.example.com", 80_i32

  # Write Payload

  request = HTTP::Request.new "GET", "http://www.example.com"
  request.to_io client

  # Read Payload

  buffer = uninitialized UInt8[4096_i32]
  length = client.read buffer.to_slice

  STDOUT.puts [:length, length]
  STDOUT.puts String.new buffer.to_slice[0_i32, length]
rescue ex
  STDOUT.puts [ex]
end

client.try &.close
require "carton"

def handle_client(context : Carton::Context)
  STDOUT.puts context.stats

  context.perform
end

# Durian

servers = [] of Durian::Resolver::Server
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("8.8.8.8", 53_i32), protocol: Durian::Protocol::UDP
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("1.1.1.1", 53_i32), protocol: Durian::Protocol::UDP

resolver = Durian::Resolver.new servers
resolver.ip_cache = Durian::Cache::IPAddress.new

# Carton

tcp_server = TCPServer.new "0.0.0.0", 1234_i32
carton = Carton::Server.new tcp_server, resolver
carton.authentication = Carton::Authentication::None
carton.client_timeout = Carton::TimeOut.new
carton.remote_timeout = Carton::TimeOut.new

# Authentication (Optional)
# carton.authentication = Carton::Authentication::Basic
# carton.on_auth = ->(user_name : String, password : String) do
#  STDOUT.puts [user_name, password]
#  Carton::Verify::Pass
# end

loop do
  socket = carton.accept?

  spawn do
    next unless client = socket
    next unless context = carton.upgrade client

    handle_client context
  end
end
STDOUT.puts context.stats # => Carton::Stats(@clientAuthentication=Basic, @destinationAddress=#<Carton::DestinationAddress:0x10c76cc20 @host="www.google.com", @port=80>, @requestPayload=#<HTTP::Request:0x10c773cb0 @method="GET", @headers=HTTP::Headers{"Host" => "www.google.com", "Proxy-Authorization" => "Basic YWRtaW46YWJjMTIz", "User-Agent" => "curl/7.68.0", "Accept" => "*/*", "Proxy-Connection" => "Keep-Alive"}, @body=nil, @version="HTTP/1.1", @cookies=nil, @query_params=nil, @uri=nil, @destinationAddress=nil, @expect_continue=false, @resource="http://www.google.com/">, @trafficType=HTTP, @tunnelMode=false)

Used as Shard

Add this to your application's shard.yml:

dependencies:
  carton:
    github: 636f7374/carton.cr

Installation

$ git clone https://github.com/636f7374/carton.cr.git

Development

$ make test

Credit

Contributors

Name Creator Maintainer Contributor
636f7374

License