I'm trying to do a simple UDP server using OCaml and the Async API but I'm stuck. I can't make this simple example work.
let wait_for_datagram () : unit Deferred.t =
let port = 9999 in
let addr = Socket.Address.Inet.create Unix.Inet_addr.localhost ~port in
let%bind socket = Udp.bind addr in
let socket = Socket.fd socket in
let stop = never () in
let config = Udp.Config.create ~stop () in
let callback buf _ : unit = failwith "got a datagram" in
Udp.recvfrom_loop ~config socket callback
I test it with:
echo -n "hello goodbye" > /dev/udp/localhost/9999
Nothing happens in my program. I tried to investigate with other tools.
I see a destination unreachable packet with Wireshark and lsof shows me this:
> lsof -i :9999
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
main.exe 77564 nemo 5u IPv4 0x25251bcc3485235f 0t0 UDP localhost:distinct
What am I doing wrong here?
The code looks ok to me. I think localhost is resolved to IPv6 address by default, and you just send it there.
Try to force using IPv4 protocol
echo -n "hello goodbye" | nc -4 -u -w0 localhost 9999
or specify explicit IPv4 address
echo -n "hello goodbye" > /dev/udp/127.0.0.1/9999
Related
I have a server with installed Postfix SMTP service, and I can send messages using bash like this:
echo "This is the body of the email" | mail -s "This is the subject line" user#example.com
But when I'm trying to do the same with Python it hangs forever:
import smtplib
s = smtplib.SMTP('localhost')
s.send_message('')
The script hangs on the second line, and it is not clear why.
I've checked the configuration of iptables (it is empty) and I still able to send messages with bash command.
"telnet localhost 25" also works fine, port is open.
Postfix config file:
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = localhost
mynetworks = 127.0.0.0/8
myorigin = /etc/mailname
send_message() expects an EmailMessage not a string. Currently it appears to hang because postfix is waiting for you to tell it to do something, you can enable debugging output using set_debuglevel().
Here's a simple example that should work:
from email.message import EmailMessage
import smtplib
msg = EmailMessage()
msg["From"] = "user#example.com"
msg["To"] = "another-user#example.com"
msg["Subject"] = "Test message subject."
msg.set_content("Test message.")
s = smtplib.SMTP("localhost")
s.set_debuglevel(1)
s.send_message(msg)
s.quit()
I bought a Orvibo S20 WIFI plug. It works great when controlled within local network. Some information on the control protocole are available here (Wifi socket communication with android phone ).
But outside of local network (from cellular or Internet), the plug control does not work.
Does someone has information on how these plugs are controlled outside of local network? Which protocole, ports are used, when do plugs update dynDNS servers...?
Thanks for help
I think the S20 communicates with an external server which routes commands from the app to the device. The reason I assume this is because when my internet connection is down my S20 is not available even from the local network via the app.
If your app isn't working outside your local network my best guess is that there may be some kind of firewall issue between the device and the external server causing the problem.
Edit: actually after further testing the app does work on the local network connection if the internet is down. Still, your issue is probably port/firewall-related.
There are two ways to send the password to the socket. Either connect to the unencrypted Wifi network created by the socket and send the password over UDP port 48899 using AT+ commands of HF-A11 (actually HF-LPB100) chip.
Or try to send password by encoding it into wifi packet lengths and repeatedly send packets of various length containing 0x05 (UDP port 49999). Socket sniffs wifi encrypted Wifi traffic and tries to determine the wifi password from that.
Some more info is available on my blog https://stikonas.eu/wordpress/2015/02/24/reverse-engineering-orvibo-s20-socket/. There are links there to some other useful posts which would give you idea how the socket works (basically sending/receiving UDP packets on port 10000).
Unfortunately, both methods of sending your password to the socket are not secure, so for security purposes you can consider your wifi password compromised.
(This is mostly a reply to Humberto Figueiredo but StackExchange rules did not allow me to post it as a comment)
I used a below script which contains a PHP script as well.
#!/bin/bash
# script to find the lan ip address mini computer
hostname -I > /tmp/plug_config_own_ip.txt
# script to find the mac addres mini computer
ifconfig eth0 | grep HWaddr >& /tmp/plug_config_own_mac.txt
# script to find the wan ip address mini computer
wget http://ipecho.net/plain -O - -q > /tmp/plug_config_own_ip_wan.txt
# script to populate the arp table
sudo nmap --send-ip -sP 192.168.1.0/24
sudo nmap --send-ip -sP 192.168.0.0/24
# script to find the ip & mac address & little endian wifi plugs
ping -c 4 HF-LPB100 && arp -n | grep ac:cf:23 >& /tmp/plug_config_wifi_socket_ip.txt
arp -n | grep ac:cf:23 >& /tmp/plug_config_wifi_socket_ip.txt
# php script to upload information into database
php /../plug_config.php > /tmp/plug_config_output.txt 2>/tmp/plug_config_error.txt &
The PHP script is basically used to create the coding to switch on / off the different WIFI sockets. This is why I need the IP, mac addresses of the WIFI sockets. Besides this PHP script stores the line of code to switch on and switch off the WIFI sockets. And later on I used this information to automatically switch on or off the devices. See PHP below:
<?php
include '/DBconfig.php';
//
// Config variables
//
$filename1 = "/tmp/plug_config_own_ip.txt";
$filename2 = "/tmp/plug_config_own_ip_wan.txt";
$filename3 = "/tmp/plug_config_own_mac.txt";
$filename4 = "/tmp/plug_config_wifi_socket_ip.txt";
$mysqli= new mysqli($host , $user , $pw ,$db);
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
if (file_exists($filename2)) {
$file = fopen($filename2,"r");
$ip_address_wan = file($filename2,FILE_IGNORE_NEW_LINES)[0];
$ip_address_wan = trim($ip_address_wan);
// echo "ip_address_wan: ".$ip_address_wan;
fclose($file);
} else {
echo "The file $filename2 does not exist";
}
if (file_exists($filename3)) {
$file = fopen($filename3,"r");
$mac_address = file($filename3,FILE_IGNORE_NEW_LINES)[0];
$mac_address = substr(strrchr($mac_address, "HWaddr "), 7);
$mac_address = trim($mac_address);
// echo "mac_address: ".$mac_address;
fclose($file);
} else {
echo "The file $filename3 does not exist";
}
// get information from wifi sockets
if (file_exists($filename4)) {
$file = fopen($filename4,"r");
$ln=1;
$device_ind = 2001;
while(! feof($file))
{
$data = fgets($file);
//echo "data: ".$data;
$ip_address = trim(substr($data, 0,15));
IF(empty($ip_address)){$device_ind=0;}
//echo "ip_address: ".$ip_address;
$mac_address = trim(substr($data,(strpos($data, "ether"))+8, 20));
// echo "mac_address: ".$mac_address;
$mac = substr($mac_address,0,2)." ".substr($mac_address,3,2)." ".substr($mac_address,6,2)." ".substr($mac_address,9,2)." ".substr($mac_address,12,2)." ".substr($mac_address,15,2);
$mac = trim($mac);
// echo "mac: ".$mac;
$little_endian = substr($mac_address,15,2)." ".substr($mac_address,12,2)." ".substr($mac_address,9,2)." ".substr($mac_address,6,2)." ".substr($mac_address,3,2)." ".substr($mac_address,0,2);
$little_endian = trim($little_endian);
// echo "little_endian: ".$little_endian;
$subscribe_code = "echo '68 64 00 1e 63 6c ".$mac." 20 20 20 20 20 20 ".$little_endian." 20 20 20 20 20 20 ' | xxd -r -p | nc -i5 -n -4u -w1 ".$ip_address." 10000";
$subscribe_code = base64_encode($subscribe_code);
//echo "subscribe_code: ".$subscribe_code;
$on_code = "echo '68 64 00 17 64 63 ".$mac." 20 20 20 20 20 20 00 00 00 00 01' | xxd -r -p | nc -i5 -n -4u -w1 ".$ip_address." 10000";
$on_code = base64_encode($on_code);
//echo "on_code: ".$on_code;
$off_code = "echo '68 64 00 17 64 63 ".$mac." 20 20 20 20 20 20 00 00 00 00 00' | xxd -r -p | nc -i5 -n -4u -w1 ".$ip_address." 10000";
$off_code = base64_encode($off_code);
//echo "off_code: ".$off_code;
//$status_code = "";
// echo "status_code: ".$status_code;
// insert information into soso_devices table
$query = "INSERT INTO soso_devices (`device_ind`,`ip_address`, `mac_address`, `mac`, `little_endian`, `subscribe_code`, `on_code`, `off_code`, `status`) VALUES ('".$device_ind."','".$ip_address."','".$mac_address."','".$mac."','".$little_endian."','".$subscribe_code."','".$on_code."','".$off_code."','Y')";
$mysqli->query($query);
//echo $query;
$device_ind++;
$ln++;
}
fclose($file);
} else {
echo "The file $filename4 does not exist";
}
mysqli_close($mysqli); // closing connection
?>
Hope this is helpfull.
I'm trying to work on following code below (code is a copy from here). Problem is that when I close the server with ctrl+c and try to run it again I get: * Exception: bind: resource busy (Address already in use).
In documentation of listenOn is written: NOTE: To avoid the "Address already in use" problems popped up several times on the GHC-Users mailing list we set the ReuseAddrsocket option on the listening socket. If you don't want this behavior, please use the lower level listen instead. Please how can I fix this? (ghci version 7.6.3)
import Network (listenOn, accept, PortID(..))
import Network.Socket (Socket, isSupportedSocketOption, SocketOption(..))
import System.IO (hSetBuffering, hGetLine, hPutStrLn, BufferMode(..), Handle)
import Control.Concurrent (forkIO)
echoImpl :: Handle -> IO ()
echoImpl client = do
line <- hGetLine client
hPutStrLn client line
echoImpl client
clientHandler :: Socket -> IO ()
clientHandler socket = do
(client, _, _) <- accept socket
hSetBuffering client NoBuffering
forkIO $ echoImpl client
clientHandler socket
felix :: IO ()
felix = do
let reuseAddrSupported = isSupportedSocketOption ReuseAddr
putStrLn $ "ReuseAddr: " ++ show reuseAddrSupported
socket <- listenOn $ PortNumber 5002
putStrLn $ "Echo server started .."
clientHandler socket
I have a very large trace file and am trying to use Wireshark to determine which dest port has the most packets sent to it. Is there a way to get counts of packets sent to particular ports? Or to sort by number of packets sent a port?
You can write a simple wireshark listener in lua.
local tap
local ports = {}
local function packet(pinfo, tvb, userdata)
-- store number of packets per each port
local port = pinfo.dst_port
ports[port] = (ports[port] or 0) + 1
end
local function draw(userdata)
local maxi,maxv = 0,0
-- print all gathered statictics and find max
for i,v in pairs(ports) do
print(i .. ":", v)
if maxv < v then
maxi,maxv = i,v
end
end
print ("Max:", maxi, maxv)
end
local function reset(userdata)
ports = {}
end
local function show_ports()
tap = Listener.new()
tap.packet = packet
tap.draw = draw
tap.reset = reset
end
register_stat_cmd_arg('ports', show_ports)
Try it:
tshark -X lua_script:ports.lua -z ports -r in.pcap
I need to know what the largest UDP packet I can send to another computer is without fragmentation.
This size is commonly known as the MTU (Maximum Transmission Unit). Supposedly, between 2 computers, will be many routers and modems that may have different MTUs.
I read that the TCP implementation in windows automatically finds the maximum MTU in a path.
I was also experimenting, and I found out that the maximum MTU from my computer to a server was 57712 bytes+header. Anything above that was discarded. My computer is on a LAN, isn't the MTU supposed to be around 1500 bytes?
The following doesn't answer your question directly but you might find it interesting; it says that IP packets can be disassembled/reassembled, and therefore bigger than limit on the underling media (e.g. 1500-byte Ethernet): Resolve IP Fragmentation, MTU, MSS, and PMTUD Issues with GRE and IPSEC
More on this topic:
Re: UDP fragmentation says you should use ICMP instead of UDP to discover MTU
Path MTU Discovery says that a TCP connection might include implicit MTU negotiation via ICMP
I don't know about generating ICMP via an API on Windows: at one time such an API was proposed, and was controversial because people argued that would make it easy to write software that implements denial-of-service functionality by generating a flood of ICMP messages.
No, it looks like it is implemented: see for example Winsock Programmer's FAQ Examples: Ping: Raw Sockets Method.
So, to discover MTU, generate ping packets with the 'do not fragment' flag.
Maybe there's an easier API than this, I don't know; but I hope I've given you to understand the underlying protocol[s].
In addition to all the previous answers, quoting the classic:
IPv4 and IPv6 define minimum reassembly buffer size, the minimum datagram size that we are guaranteed any implementation must support. For IPv4, this is 576 bytes. IPv6 raises this to 1,280 bytes.
This pretty much means that you want to limit your datagram size to under 576 if you work over public internet and you control only one side of the exchange - that's what most of the standard UDP-based protocols do.
Also note that PMTU is a dynamic property of the path. This is one of the things TCP deals with for you. Unless you are ready to re-implement lots of sequencing, timing, and retransmission logic, use TCP for any critical networking. Benchmark, test, profile, i.e. prove that TCP is your bottleneck, only then consider UDP.
This is an interesting topic for me. Perhaps some practical results might be of interest when delivering chunky UDP data around the real world internet via UDP, and with a transmission rate of 1 packet a second, data continues to turn up with minimal packet loss up to about 2K. Over this and you start running into issues, but regularly we delivered 1600+ bytes packets without distress - this is over GPRS mobile networks as well as WAN world wide. At ~1K assuming the signal is stable (its not!) you get low packet loss.
Interestingly its not the odd packet, but often a squall of packets for a few seconds - which presumably is why VoIP calls just collapse occasionally.
Your own MTU is available in the registry, but the MTU in practice is going to the smallest MTU in the path between your machine and the destination. Its both variable and can only be determined empirically. There are a number of RFCs showing how to determine it.
LAN's can internally have very large MTU values, since the network hardware is typically homogeneous or at least centrally administrated.
For UDP applications you must handle end-to-end MTU yourself if you want to avoid IP fragmentation or dropped packets. The recommended approach for any application is to do your best to use PMTU to pick your maximum datagram, or send datagrams < minimum PMTU
https://www.rfc-editor.org/rfc/rfc5405#section-3.2
Unicast UDP Usage Guidelines for Application Designers "SHOULD NOT send datagrams that exceed the PMTU, SHOULD discover PMTU or send datagrams < minimum PMTU
Windows appears to settings and access to PMTU information via it's basic socket options interface:
You can make sure PMTU discover is on via IP_MTU_DISCOVER, and you can read the MTU via IP_MTU.
https://learn.microsoft.com/en-us/windows/desktop/winsock/ipproto-ip-socket-options
Here's a bit of Windows PowerShell that I wrote to check for Path MTU issues. (The general technique is not too hard to implement in other programming languages.) A lot of firewalls and routers are configured to drop all ICMP by people who don't know any better. Path MTU Discovery depends on being able to receive an ICMP Destination Unreachable message with Fragementation Needed set in response to sending a packet with Don't Fragment set. The Resolve IPv4 Fragmentation, MTU, MSS, and PMTUD Issues with GRE and IPsec actually does a really good job of explaining how discovery works.
function Test-IPAddressOrName($ipAddressOrName)
{
$ipaddress = $null
$isValidIPAddressOrName = [ipaddress]::TryParse($ipAddressOrName, [ref] $ipaddress)
if ($isValidIPAddressOrName -eq $false)
{
$hasResolveDnsCommand = $null -ne (Get-Command Resolve-DnsName -ErrorAction SilentlyContinue)
if ($hasResolveDnsCommand -eq $true)
{
$dnsResult = Resolve-DnsName -DnsOnly -Name $ipAddressOrName -ErrorAction SilentlyContinue
$isValidIPAddressOrName = $null -ne $dnsResult
}
}
return $isValidIPAddressOrName
}
function Get-NameAndIPAddress($ipAddressOrName)
{
$hasResolveDnsCommand = $null -ne (Get-Command Resolve-DnsName -ErrorAction SilentlyContinue)
$ipAddress = $null
$validIPAddress = [ipaddress]::TryParse($ipAddressOrName, [ref] $ipAddress)
$nameAndIp = [PSCustomObject] #{ 'Name' = $null; 'IPAddress' = $null }
if ($validIPAddress -eq $false)
{
if ($hasResolveDnsCommand -eq $true)
{
$dnsResult = Resolve-DnsName -DnsOnly $ipAddressOrName -Type A -ErrorAction SilentlyContinue
if ($null -ne $dnsResult -and $dnsResult.QueryType -eq 'A')
{
$nameAndIp.Name = $dnsResult.Name
$nameAndIp.IPAddress = $dnsResult.IPAddress
}
else
{
Write-Error "The name $($ipAddressOrName) could not be resolved."
$nameAndIp = $null
}
}
else
{
Write-Warning "Resolve-DnsName not present. DNS resolution check skipped."
}
}
else
{
$nameAndIp.IPAddress = $ipAddress
if ($hasResolveDnsCommand -eq $true)
{
$dnsResult = Resolve-DnsName -DnsOnly $ipAddress -Type PTR -ErrorAction SilentlyContinue
if ($null -ne $dnsResult -and $dnsResult.QueryType -eq 'PTR')
{
$nameAndIp.Name = $dnsResult.NameHost
}
}
}
return $nameAndIp
}
<#
.Synopsis
Performs a series of pings (ICMP echo requests) with Don't Fragment specified to discover the path MTU (Maximum Transmission Unit).
.Description
Performs a series of pings with Don't Fragment specified to discover the path MTU (Maximum Transmission Unit). An ICMP echo request
is sent with a random payload with a payload length specified by the PayloadBytesMinimun. ICMP echo requests of increasing size are
sent until a ping response status other than Success is received. If the response status is PackeTooBig, the last successful packet
length is returned as a reliable MTU; otherwise, if the respone status is TimedOut, the same size packet is retried up to the number
of retries specified. If all of the retries have been exhausted with a response status of TimedOut, the last successful packet
length is returned as the assumed MTU.
.Parameter UseDefaultGateway
If UseDefaultGateway is specified the default gateway reported by the network interface is used as the destination host.
.Parameter DestinationHost
The IP Address or valid fully qualified DNS name of the destination host.
.Parameter InitialTimeout
The number of milliseconds to wait for an ICMP echo reply. Internally, this is doubled each time a retry occurs.
.Parameter Retries
The number of times to try the ping in the event that no reply is recieved before the timeout.
.Parameter PayloadBytesMinimum
The minimum number of bytes in the payload to use. The minimum MTU for IPv4 is 68 bytes; however, in practice, it's extremely rare
to see an MTU size less than 576 bytes so the default value is 548 bytes (576 bytes total packet size minus an ICMP header of 28
bytes).
.Parameter PayloadBytesMaximum
The maximum number of bytes in the payload to use. An IPv4 MTU for jumbo frames is 9000 bytes. The default value is 8973 bytes (9001
bytes total packet size, which is 1 byte larger than the maximum IPv4 MTU for a jumbo frame, minus an ICMP header of 28 bytes).
.Example
Discover-PathMTU -UseDefaultGateway
.Example
Discover-PathMTU -DestinationHost '192.168.1.1'
.Example
Discover-PathMTU -DestinationHost 'www.google.com'
#>
function Discover-PathMtu
{
[CmdletBinding(SupportsShouldProcess = $false)]
param
(
[Parameter(Mandatory = $true, ParameterSetName = 'DefaultGateway')]
[switch] $UseDefaultGateway,
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ParameterSetName = 'IPAddressOrName')]
[ValidateScript({ Test-IPAddressOrName $_ })]
[string] $DestinationHost,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
[int] $InitialTimeout = 3000,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
[int] $Retries = 3,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
$PayloadBytesMinimum = 548,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
$PayloadBytesMaximum = 8973
)
begin
{
$ipConfiguration = Get-NetIPConfiguration -Detailed | ?{ $_.NetProfile.Ipv4Connectivity -eq 'Internet' -and $_.NetAdapter.Status -eq 'Up' } | Sort { $_.IPv4DefaultGateway.InterfaceMetric } | Select -First 1
$gatewayIPAddress = $ipConfiguration.IPv4DefaultGateway.NextHop
$pingOptions = New-Object System.Net.NetworkInformation.PingOptions
$pingOptions.DontFragment = $true
$pinger = New-Object System.Net.NetworkInformation.Ping
$rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
}
process
{
$pingIpAddress = $null
if ($UseDefaultGateway -eq $true)
{
$DestinationHost = $gatewayIPAddress
}
$nameAndIP = Get-NameAndIPAddress $DestinationHost
if ($null -ne $nameAndIP)
{
Write-Host "Performing Path MTU discovery for $($nameAndIP.Name) $($nameAndIP.IPAddress)..."
$pingReply = $null
$payloadLength = $PayloadBytesMinimum
$workingPingTimeout = $InitialTimeout
do
{
$payloadLength++
# Use a random payload to prevent compression in the path from potentially causing a false MTU report.
[byte[]] $payloadBuffer = (,0x00 * $payloadLength)
$rng.GetBytes($payloadBuffer)
$pingCount = 1
do
{
$pingReply = $pinger.Send($nameAndIP.IPAddress, $workingPingTimeout, $payloadBuffer, $pingOptions)
if ($pingReply.Status -notin 'Success', 'PacketTooBig', 'TimedOut')
{
Write-Warning "An unexpected ping reply status, $($pingReply.Status), was received in $($pingReply.RoundtripTime) milliseconds on attempt $($pingCount)."
}
elseif ($pingReply.Status -eq 'TimedOut')
{
Write-Warning "The ping request timed out while testing a packet of size $($payloadLength + 28) using a timeout value of $($workingPingTimeout) milliseconds on attempt $($pingCount)."
$workingPingTimeout = $workingPingTimeout * 2
}
else
{
Write-Verbose "Testing packet of size $($payloadLength + 28). The reply was $($pingReply.Status) and was received in $($pingReply.RoundtripTime) milliseconds on attempt $($pingCount)."
$workingPingTimeout = $InitialTimeout
}
Sleep -Milliseconds 10
$pingCount++
} while ($pingReply.Status -eq 'TimedOut' -and $pingCount -le $Retries)
} while ($payloadLength -lt $PayloadBytesMaximum -and $pingReply -ne $null -and $pingReply.Status -eq 'Success')
if ($pingReply.Status -eq 'PacketTooBig')
{
Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27)."
}
elseif ($pingReply.Status -eq 'TimedOut')
{
Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27), but may not be reliable because the packet appears to have been discarded."
}
else
{
Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27), but may not be reliable, due to an unexpected ping reply status."
}
return $payloadLength + 27
}
else
{
Write-Error "The name $($DestinationHost) could not be resolved. No Path MTU discovery will be performed."
}
}
end
{
if ($null -ne $pinger)
{
$pinger.Dispose()
}
if ($null -ne $rng)
{
$rng.Dispose()
}
}
}