Golang: How to simulate a POST with a form request? - go

I've been scouring the internet and can't find much at all about posting forms in golang tests. This is my attempt at it. I get the error "dial tcp: too many colons in address ::1" though. If I change the address to "http://localhost:8080/" I get "dial tcp 127.0.0.1:8080: connection refused".
I've read that if you put the (IPv6) address in brackets, the brackets will fix the problem, but then I get the error unrecognized protocol.
var addr = "http://::1/"
h := handlers.GetHandler()
server := httptest.NewServer(h)
server.URL = addr
req, err := http.PostForm(addr+"login",
url.Values{"username": {"lemonparty"}, "password": {"bluewaffle"}})
if err != nil {
log.Fatal(err)
}

tl;dr the Listener in httptest.Server doesn't use the httptest.Server.URL as the url to listen on. It doesn't care what that value is. It listens on local hosts lowest open port number.
The URL property on httptest.Server is not really doing anything. Change it all you want, just don't send your requests there. Check out this example program https://play.golang.org/p/BsH38WLkrJ
Basically, if I change the servers URL then send the request to the value I set it to it doesn't work, but if I send it to the default value it does.
Also check out the source http://golang.org/src/net/http/httptest/server.go?s=415:1018#L65, as well as the certs at the bottom of the file; clearly hard coded for the lowest open port on local host. If you want to make request to another URL the Listener.

Related

Difference between NewChannel vs Request in ssh sftp server

I'm looking at go sftp server example code
https://github.com/pkg/sftp/blob/master/examples/go-sftp-server/main.go
There are section of code which are unclear to me
_, chans, reqs, err := ssh.NewServerConn(nConn, config)
if err != nil {
log.Fatal("failed to handshake", err)
}
fmt.Fprintf(debugStream, "SSH server established\n")
// The incoming Request channel must be serviced.
go ssh.DiscardRequests(reqs)
// Service the incoming Channel channel.
for newChannel := range chans {
...
}
First: With ssh.NewServerConn, if NewChannel(chans) represent new request to the channel what is Request reqs. So what is difference between chans and reqs here.
Second: Why is the need to ssh.DiscardRequests(reqs)
Looking at the documentation for ssh.NewServerConn it appears that it returns the following:
*ServerConn
<-chan NewChannel
<-chan *Request
error
The second returned value, NewChannel
represents an incoming request to a channel
The third returned value, Request
is a request sent outside of the normal stream of data
This doesn't really answer your questions but it does provide helpful clues as where to look.
So to answer you questions:
chans receives connections that are new to the server. Using the received value from chans, you can either accept and communicate with that connection or just reject the connection. This can be thought of multiple people logging into a remote machine via ssh and handling multiple sessions.
reqs holds global requests (which is defined here) sent to either the server or client that should not be sent to any specific channel. RFC4254 gives the example of a such a request as "start TCP/IP forwarding for a specific port".
You can see the internal usage of how the ssh package uses the incomingRequests channel here.
The documentation for ssh.NewServerConn explicitly states
The Request and NewChannel channels must be serviced, or the connection will hang.
In the event that this server does receive a global request it needs to be handled appropriately if the request is asking for a reply.
Apart from #will7200 answer I just want to add a couple of things which I found while my reading around this.
SSH has Global request called SSH_MESSAGE_GLOBAL_REQUEST and SSH_MESSAGE_CHANNEL_REQUEST or starts TCP/IP forwarding for a specific port
a channel is any specific terminal or how we see it when we send the data across the ssh server and client.
So reqs over here is the global request and all channel requests are wrapped inside the channel.
GLOBAL requests are requests that are not specific to a CHANNEL like TCPKeepAlive (as mention in ssh_config) or start TCP/IP forwarding for a specific port.
and DisdCardRequest essentially discard those request that does not want a reply

How to connect with TCP to different hosts from the same source ip and port

I would like to initiate TCP connections between a process and other processes which are already listening from incoming TCP connections.
I would like to use the same source address (ip-port) for these connections.
I am programming in Go.
I tried to run this code, but the second DialTCP call fails.
func main() {
ourAddr, _ := net.ResolveTCPAddr("tcp", "localhost:51234")
otherAddr1, _ := net.ResolveTCPAddr("tcp", "localhost:51236")
otherAddr2, _ := net.ResolveTCPAddr("tcp", "localhost:51237")
conn1, err1 := net.DialTCP("tcp", ourAddr, otherAddr1)
if err1 != nil {
log.Fatal("err1: " + err1.Error())
}
defer conn1.Close()
conn2, err2 := net.DialTCP("tcp", ourAddr, otherAddr2) // <- this fails
if err2 != nil {
log.Fatal("err2: " + err2.Error())
}
defer conn2.Close()
}
The error message is: err2: dial tcp 127.0.0.1:51234->127.0.0.1:51237: bind: address already in use
(the problem should not be related to the destination processes since two instances of netcat are already listening on the destination addresses)
I also tried using other ports (in case they were still in use) and it failed the same way
Here is my go version:
go version go1.13.4 linux/amd64
It seems to me the problem is not related to TCP but to the way I am using the Go library.
What am I doing wrong, and how am I supposed to do?
The problem you are facing is a general one, not related to Go programming language.
To my knowedge, you should not be able to connect to two destinations from the same source IP address and Port. I am pretty sure this is backed up by the message you get.
err2: dial tcp 127.0.0.1:51234->127.0.0.1:51237: bind: address already in use
It is not complaining about your destination address. It is complaining about the source address 127.0.0.1:51234. Try to change your source address and see what happens.
Edit: It appears that there are socket options SO_REUSEADDR and SO_REUSEPORT that allow that but are non-standardized and appear to be used under verify specific load-intensive scenarios.
It would help to know why you want to achieve such a setup.
Addition: There is a stackoverflow question that is related to your problem: TCP: can two different sockets share a port?

How to pick up IP packets and inject on different VM and interface

I have been trying to solve these 2 problems, but without success.
I wonder if it's possible to remove specific packets from an interface with Gopacket or is it just for listening on the wire? For example when I send a UDP packet to a wrong port and then with Gopacket I correct it, it will send 2 packets, 1 to the wrong port and 1 to the correct one. Is there a way to discard/drop the wrong packet with Gopacket?
What I am trying to do, is to pick up all packets that are sent by a client over IP and then encapsulate each packet as a payload in another protocol X and send to the remote host which will receive on protocol X, get the payload and send it on its interface to reach the server over IP again. (IP (Client) -> Protocol X (Sniffer 1) -> Protocol X (Sniffer 2) -> IP (Server))
I have verified that the packet which Sniffer 1 picks up from the Client's interface is the same which arrives at Sniffer 2, but the problem is when Sniffer 2 injects it on the Server's interface. I can't see that packet with tcpdump or any other tool. The packet is injected with this command:
if handle, err := pcap.OpenLive("enp0s8", 1600, true, 100); err != nil {
panic(err)
} else {
err = handle.WritePacketData(packet.Data())
}
If the Protocol X part is avoided, then the server will receive messages from client, but with Protocol X it is not possible.
Thanks in advance!
According to the Documentation
Package pcap allows users of gopacket to read packets off the wire or
from pcap files.
To discard packages, you will need to be able to intercept them. Depending on how generic you want to solve this problem, you probably need to hook into the kernel. I recommend looking into iptables and netfilters.
I found some VPN that are written in go, maybe look into how they are built, as you want to do something similar (tunnelling of packets).

Boost::asio UDP Broadcast with ephemeral port

I'm having trouble with udp broadcast transactions under boost::asio, related to the following code snippet. Since I'm trying to broadcast in this instance, so deviceIP = "255.255.255.255". devicePort is a specified management port for my device. I want to use an ephemeral local port, so I would prefer if at all possible not to have to socket.bind() after the connection, and the code supports this for unicast by setting localPort = 0.
boost::asio::ip::address_v4 targetIP = boost::asio::ip::address_v4::from_string(deviceIP);
m_targetEndPoint = boost::asio::ip::udp::endpoint(targetIP, devicePort);
m_ioServicePtr = boost::shared_ptr<boost::asio::io_service>(new boost::asio::io_service);
m_socketPtr = boost::shared_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(*m_ioServicePtr));
m_socketPtr->open(m_targetEndPoint.protocol());
m_socketPtr->set_option(boost::asio::socket_base::broadcast(true));
// If no local port is specified, default parameter is 0
// If local port is specified, bind to that port.
if(localPort != 0)
{
boost::asio::ip::udp::endpoint localEndpoint(boost::asio::ip::address_v4::any(), localPort);
m_socketPtr->bind(localEndpoint);
}
if(m_forceConnect)
m_socketPtr->connect(m_targetEndPoint);
this->AsyncReceive(); // Register Asynch Recieve callback and buffer
m_socketThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&MyNetworkBase::RunSocketThread, this))); // Start thread running io_service process
No matter what I do in terms of the following settings, the transmit is working fine, and I can use Wireshark to see the response packets coming back from the device as expected. These response packets are also broadcasts, as the device may be on a different subnet to the pc searching for it.
The issues are extremely strange to my mind, but are as follows:
If I specify the local port and set m_forceConnect=false, everything works fine, and my recieve callback fires appropriately.
If I set m_forceConnect = true in the constructor, but pass in a local port of 0, the transmit works fine, but my receive callback never fires. I would assume this is because the 'target' (m_targetEndpoint) is 255.255.255.255, and since the device has a real IP, the response packet gets filtered out.
(what I actually want) If m_forceConnect = false (and data is transmitted using a send_to call), and local port = 0, therefore taking an ephemeral port, my RX callback immediately fires with an error code 10022, which I believe is an "Invalid Argument" socket error.
Can anyone suggest why I can't use the connection in this manner (not explicitly bound and not explicitly connected)? I obviously don't want to use socket.connect() in this case, as I want to respond to anything I receive. I also don't want to use a predefined port, as I want the user to be able to construct multiple copies of this object without port conflicts.
As some people may have noticed, the overall aim of this is to use the same network-interface base-class to handle both the unicast and broadcast cases. Obviously for the unicast version, I can perfectly happily m_socket->connect() as I know the device's IP, and I receive the responses since they're from the connected IP address, therefore I set m_forceConnect = true, and it all just works.
As all my transmits use send_to, I have also tried to socket.connect(endpoint(ip::addressv4::any(), devicePort), but I get a 'The requested address is not valid in its context' exception when I try it.
I've tried a pretty serious hack:
boost::asio::ip::udp::endpoint localEndpoint(boost::asio::ip::address_v4::any(), m_socketPtr->local_endpoint().port());
m_socketPtr->bind(localEndpoint);
where I extract the initial ephemeral port number and attempt to bind to it, but funnily enough that throws an Invalid Argument exception when I try and bind.
OK, I found a solution to this issue. Under linux it's not necessary, but under windows I discovered that if you are neither binding nor connecting, you must have transmitted something before you make the call to asynch_recieve_from(), the call to which is included within my this->asynch_receive() method.
My solution, make a dummy transmission of an empty string immediately before making the asynch_receive call under windows, so the modified code becomes:
m_socketPtr->set_option(boost::asio::socket_base::broadcast(true));
// If no local port is specified, default parameter is 0
// If local port is specified, bind to that port.
if(localPort != 0)
{
boost::asio::ip::udp::endpoint localEndpoint(boost::asio::ip::address_v4::any(), localPort);
m_socketPtr->bind(localEndpoint);
}
if(m_forceConnect)
m_socketPtr->connect(m_targetEndPoint);
// A dummy TX is required for the socket to acquire the local port properly under windoze
// Transmitting an empty string works fine for this, but the TX must take place BEFORE the first call to Asynch_receive_from(...)
#ifdef WIN32
m_socketPtr->send_to(boost::asio::buffer("", 0), m_targetEndPoint);
#endif
this->AsyncReceive(); // Register Asynch Recieve callback and buffer
m_socketThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&MyNetworkBase::RunSocketThread, this)));
It's a bit of a hack in my book, but it is a lot better than implementing all the requirements to defer the call to the asynch recieve until after the first transmission.

Use raw sockets in Go

I'm trying to write a program that receives DHCP discoveries (UDP) and forwards them on to a given IP address using a different source IP address depending on the content of a specific field (GIADDR) in the DHCP packet.
I could get working the receiving and sending bit but I'm having an issue with using as IP source address anything that is not a configured IP address on the local machine.
I believe that this can only be done using Raw sockets; is that true ?
Are there any examples out there on how to do that in Go ?
I've spent a couple of days looking around but could not find much.
Cheers,
Sal
There are a number of hurdles to jump with what you propose:
Security
In general, being able to set the source IP address for a packet could be a very dangerous thing security wise. Under linux, in order to forge your own raw DHCP packets with custom headers, you will need to run your application as root or from an application with the CAP_NET_RAW capability (see setcap).
Raw Sockets in Go
The standard net library does not provide raw socket capability because it is very specialized and the API may be subject to change as people begin to use it in anger.
The go.net subrepository provides an ipv4 and an ipv6 package, the former of which should suit your needs:
http://godoc.org/code.google.com/p/go.net/ipv4#NewRawConn
Header Spoofing
You will need to use ipv4.RawConn's ReadFrom method to read your source packet. You should then be able to use most of those fields, along with your GIADDR logic, to set up the headers for the WriteTo call. It will probably look something like:
for {
hdr, payload, _, err := conn.ReadFrom(buf)
if err != nil { ... }
hdr.ID = 0
hdr.Checksum = 0
hdr.Src = ...
hdr.Dst = ...
if err := conn.WriteTo(hdr, payload, nil); err != nil { ... }
}

Resources