I'm getting itermittent data loss when calling .NET [Console]::ReadLine() to read piped input to PowerShell.exe. In CMD, run:
>ping localhost | powershell -NonInteractive -NoProfile -C "do {$line = [Console]::ReadLine(); ('' + (Get-Date -f 'HH:mm
:ss') + $line) | Write-Host; } while ($line -ne $null)"
23:56:45time<1ms
23:56:45
23:56:46time<1ms
23:56:46
23:56:47time<1ms
23:56:47
23:56:47
Normally 'ping localhost' from Vista64 looks like this, so there is a lot of data missing from the output above:
Pinging WORLNTEC02.bnysecurities.corp.local [::1] from ::1 with 32 bytes of data:
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Ping statistics for ::1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
But using the same API from C# receives all the data sent to the process (excluding some newline differences). Code:
namespace ConOutTime {
class Program {
static void Main (string[] args) {
string s;
while ((s = Console.ReadLine ()) != null) {
if (s.Length > 0) // don't write time for empty lines
Console.WriteLine("{0:HH:mm:ss} {1}", DateTime.Now, s);
}
}
}
}
Output:
00:44:30 Pinging WORLNTEC02.bnysecurities.corp.local [::1] from ::1 with 32 bytes of data:
00:44:30 Reply from ::1: time<1ms
00:44:31 Reply from ::1: time<1ms
00:44:32 Reply from ::1: time<1ms
00:44:33 Reply from ::1: time<1ms
00:44:33 Ping statistics for ::1:
00:44:33 Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
00:44:33 Approximate round trip times in milli-seconds:
00:44:33 Minimum = 0ms, Maximum = 0ms, Average = 0ms
So, if calling the same API from PowerShell instead of C# many parts of StdIn get 'eaten'. Is the PowerShell host reading string from StdIn even though I didn't use 'PowerShell.exe -Command -'?
You can use the $input enumerator in PowerShell to get access to data piped into the program. I also have found that [Console]::ReadLine() somehow does little to nothing. Unknown reasons for that, though.
C:\Users\Me> ping localhost | powershell -noninteractive -noprofile -c "$input|%{(date -f HH:mm:ss)+' '+$_}"
07:31:54
07:31:54 Pinging Sigmund [::1] with 32 bytes of data:
07:31:54 Reply from ::1: time<1ms
07:31:54 Reply from ::1: time<1ms
07:31:54 Reply from ::1: time<1ms
07:31:55 Reply from ::1: time<1ms
07:31:55
07:31:55 Ping statistics for ::1:
07:31:55 Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
07:31:55 Approximate round trip times in milli-seconds:
07:31:55 Minimum = 0ms, Maximum = 0ms, Average = 0ms
C:\Users\Me>ping localhost
Pinging Sigmund [::1] with 32 bytes of data:
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Ping statistics for ::1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
One possible solution is this one:
powershell -NonInteractive -NoProfile -C "ping localhost | % { ('' + (Get-Date -f 'HH:mm:ss') + $_) | Write-Host; }"
I'm adding it for other question visitors, cause I think you had some reasons why you don't use that :)
I'm submitting my final solution, even if it wasn't really an answer to my initial question. I was trying to pipe data to powershell from a cmd.exe environment that had a bunch of specialized tools (see www.streambase.com). Eventually I added the tools into my powershell environment.
I ended up calling the external tool from within PowerShell and piping to Out-Time advanced function...
function Out-Time {
param (
[parameter(ValueFromPipeline=$true)]
$Value,
[switch] $OutputEmptyLines=$false)
process {
if (!$OutputEmptyLines -and ($Value -eq $null -or $Value -eq '')) {
}
else {
"{0} {1}" -f #((get-date -Format "HH:mm:ss.ff"), $Value)
}
}
}
#test
#ping localhost | Out-Time; ping localhost | Out-Time -OutputEmpty
Related
So I'm trying to do a mock Traceroute function where a UDP packet is sent to an IP address. I'm trying to design the program in such a way where a packet is sent each time the packet makes it to a router. I am trying to do this by making a very short TTL. However, the recvfrom function is stalling.
Here's the code:
host_addr = gethostbyname(host)
port = 33434
max_hops = 30
ttl = 1
while True:
recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)
send_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
send_socket.setsockopt(0, 4, ttl)
recv_socket.bind(("", port))
send_socket.sendto("waddup".encode(), (host_addr, port))
cur_addr = None
cur_name = None
path_end = False
cur_bytes = None
attempts_left = 3
timeReceived = 0
pingStartTime = 0
while not path_end and attempts_left > 0:
try:
pingStartTime = time.time()
cur_bytes, cur_addr = recv_socket.recvfrom(1024)
timeReceived = time.time()
path_end = True
cur_addr = cur_addr[0]
try:
cur_name = gethostbyaddr(cur_addr)[0]
except error:
cur_name = cur_addr
except error:
attempts_left -= 1
send_socket.close()
recv_socket.close()
if not path_end:
pass
if cur_addr is not None:
cur_host = "%s (%s) " % (cur_name, cur_addr)
else:
cur_host = ""
print("%d: %.0f ms " %
(
ttl,
(timeReceived - pingStartTime) * 1000,
) + cur_host
)
ttl += 1
if cur_addr == host_addr or ttl > max_hops:
break
I have set up the receiving socket for an ICMP packet as far as I can tell but it just hangs on recvfrom. I've allowed all ICMP connections on Windows Defender and when I run Wireshark, an appropriate ICMP packet is sent to my router.
The packet with the TTL expired message is the one I want to receive
I'm new to networking but all the code I've seen online has this exact setup. Would anyone be able to tell me why it's stalling and what I can do to fix it? I want the program to read the ICMP packet with the TTL expiration message.
I have a simple udp server/client setup where I send a message from the client and print it on the server. This works well for a regular IP packet but the message is not received when I add an IP options header to the packet, even though I can sniff the packet using scapy.
Here's the packet without IP options
###[ Ethernet ]###
dst = 00:04:00:00:04:01
src = 00:aa:00:02:00:04
type = 0x800
###[ IP ]###
version = 4L
ihl = 5L
tos = 0x0
len = 47
id = 1
flags =
frag = 0L
ttl = 61
proto = udp
chksum = 0x62f4
src = 10.0.2.101
dst = 10.0.4.101
\options \
###[ UDP ]###
sport = 10001
dport = 3478
len = 27
chksum = 0x2bd1
###[ Raw ]###
load = 'message from a game'
And here's the packet with IP options header:
###[ Ethernet ]###
dst = 00:04:00:00:04:01
src = 00:aa:00:02:00:04
type = 0x800
###[ IP ]###
version = 4L
ihl = 8L
tos = 0x0
len = 59
id = 1
flags =
frag = 0L
ttl = 61
proto = udp
chksum = 0x5fe8
src = 10.0.2.101
dst = 10.0.4.101
\options \
|###[ IPOption ]###
| copy_flag = 1L
| optclass = control
| option = 31L
| length = 12
| value = '\x00\x01\x00\x00RTGAME'
###[ UDP ]###
sport = 10001
dport = 3478
len = 27
chksum = 0x2bd1
###[ Raw ]###
load = 'message from a game'
And here's the UDP server:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', args.port))
while True:
try:
data, addr = sock.recvfrom(1024)
print("received: %s" % data)
except KeyboardInterrupt:
sock.close()
break
I've been stuck on this for a few days and would love if someone could figure it out.
Thanks
have just been playing and the following works as a self-contained/minimal working example for me with Python 3.7.1 under both OSX and Linux
generating a valid set of IP Options:
from scapy.all import IPOption, raw
ipopts = raw(IPOption(
copy_flag=1, optclass='control', option=31,
value='\x00\x01\x00\x00RTGAME'))
(if you don't have Scapy, the above should generate: b'\x9f\x0c\x00\x01\x00\x00RTGAME')
client code:
import socket
from time import sleep
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(('127.0.0.1', 3478))
s.setsockopt(socket.IPPROTO_IP, socket.IP_OPTIONS, ipopts)
while True:
s.send(b'message from a game')
sleep(1)
server code:
import socket
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.bind(('', 3478))
s.setsockopt(socket.IPPROTO_IP, socket.IP_RECVOPTS, 1)
while True:
print(*s.recvmsg(4096, 1024))
this should result in the "server" displaying lines like:
b'message from a game\n' [(0, 6, b'\x9f\x0c\x00\x01\x00\x00RTGAME')] 0 ('127.0.0.1', 46047)
furthermore, I can watch packets move over the network by running:
sudo tcpdump -i lo0 -vvv -n 'udp and port 3478'
at the command line, or this in Scapy:
sniff(iface='lo0', filter='udp and port 3478', prn=lambda x: x.show())
for some reason I don't actually receive the ancillary data containing the IP Options under OSX, but the data shows up in the packet sniffers.
The problem was due to an incorrect IPv4 checksum. I failed to mention in the question that I'm running this in a mininet environment with custom switches. The IP options get added in transit by a switch, but the checksum wasn't updated. Once I fixed that, the packet made it to the server.
Thanks for the help and pointers everyone!
First time attempting to work with UDP. I'm harvesting lat/long from a NMEA string in a UDP broadcast. The code below works fine in the ISE but hangs up in the console. I'm running both with Admin rights. Other posts on the topic recommend dot-sourcing, no difference. I suspect it's something to do with how it's handling variables but have hit a wall. Thanks in advance for help.
##########################################################################
#
# Read $GPGGA string from UDP broadcast on port 40181
#
# Convert Degree-Minutes-Seconds format to decimal lat/long
#
# UDP code harvested from http://winpowershell.blogspot.com/2010/01/powershell-udp-clientserver.html
#
#
##########################################################################
# Form a connection point
$endpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)
Write-Host "Endpoint: " $endpoint
# Open UDP client
$udpclient = new-Object system.Net.Sockets.Udpclient(40181)
Write-Host "UDP client: " $udpclient
# Grab the datagram
$content = $udpclient.Receive([ref]$endpoint)
Write-Host "Content: " $content
# Put the datagram in $udpstring as type string
$udpstring = [Text.Encoding]::ASCII.GetString($content)
Write-Host "UDP string: " $udpstring
# Close UDP client
$udpclient.Close()
# Get Degree Min Sec format latitude from UDP string
# Explicit typing required in order to do math later
[Double]$DMSlatdeg = $udpstring.Substring(17,2)
$DMSlatmin = $udpstring.Substring(19,2)
# Get North South directional from UDP string
$directNS = $udpstring.Substring(29,1)
# Get Degree Min Sec format longitude from UDP string
# Explicit typing required in order to do math later
[Double]$DMSlongdeg = $udpstring.Substring(31,3)
$DMSlongmin = $udpstring.Substring(34,2)
# Get East West directional from UDP string
$directEW = $udpstring.Substring(44,1)
# Add decimal latitude minutes value to degrees
$declat = ($DMSlatdeg + ($DMSlatmin/60))
# Add decimal longitude minutes value to degrees
$declong = ($DMSlongdeg + ($DMSlongmin/60))
# Output formatted to three decimal places - variable value not changed
Write-Host "Decimal lat: " $declat.ToString("#.###") $directNS
Write-Host "Decimal long: " $declong.ToString("#.###") $directEW
In ISE I get the correct output:
Endpoint: 0.0.0.0:0
UDP client: System.Net.Sockets.UdpClient
Content: 36 71 80 71 71 65 44 [etc]
UDP string: $GPGGA,160516.13,[etc]
Decimal lat: [correct value] N
Decimal long: [correct value] W
In the console, it gets out the first two statements and hangs:
Endpoint: 0.0.0.0:0
UDP client: System.Net.Sockets.UdpClient
Is there something wrong with the way I'm setting $content?
I am using Net::Ping to check the network availability. When I run the code, it returns response. But when I recheck using command prompt, it is time out.
The Code :
$p = Net::Ping->new('tcp');
$p->hires();
($ret, $duration, $ip) = $p->ping($host);
if ($ret){
printf("$host [ip: $ip] is alive (packet return time: %.2f ms)\n", 1000 * $duration);
}else{
printf("time out");
}
Result :
10.10.x.x [ip: 10.10.x.x] is alive (packet return time: 18.72 ms)
Using command prompt :
C:\ping 10.10.x.x -t
Pinging 10.10.x.x with 32 bytes of data:
Request timed out.
Any explanation and advice would be appreciated
Im trying to write a script that uses tcpdump under openbsd than monitor firewall logs.
My goal is to genereate an alert if a source ip address is equal to evry line [ line duplicate ] from the tcpdump output, example :
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 1, length 64
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 2, length 64
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 3, length 64
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 4, length 64
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 5, length 64
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 6, length 64
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 7, length 64
rule 30/0(match): block in on pppoe0: SRCIP:(88.198.46.51) -> DESTIP:(109.226.27.19): ICMP echo request, id 1070, seq 8, length 64
ip 88.198.46.51 is attempted dos attack.
my code so far:
open(SNIFF, "/usr/sbin/tcpdump -s 1024 -enlti pflog0 |");
while(<SNIFF>){
$|++;
$_ =~ /(\d+.\d+.\d+.\d+)(.)(\d{2,5}) (>) (\d+\.\d+\.\d+\.\d+)(.)(\d{2,5})/;
my ($sip, $port) = ($1, $7);
my $bad_ip = $sip;
if($bad_ip eq $p_ip){
$count++;
if($count >= 8 && $print){
print "Attack Detected: $sip\n";
system("echo $sip");
#system("/sbin/pfctl -f /etc/pf.conf");
$print = 0;
}
In your sample input, I don't see a single line that matches the first part of your regex:
/(\d+\.\d+\.\d+\.\d+)(\.)(\d{2,5})/
(Note, that I anticipated that if you're looking for a dotted decimal, that you really want \d+\. not just \d+..)
You can match (\d+\.\d+\.\d+\.\d+) with your input, but the rest is not going to match. That's your issue.