Using STDIN/STDOUT as a socket - perl

I'm having a client process launch a server process with xinetd. As I understand it, the server come to life being able to read from the client via its STDIN, and write to the client via its STDOUT. For various reasons (mainly having the server be able to use select() and then read() or recv() ) I want to be able to somehow transform STDIN and STDOUT into a socket and then perform ordinary socket I/O on it, as I will with the other servers that my server will connect to.
Can this be done? Is this even a meaningful question?

All the function calls you mention can be used on the file descriptors with the numbers STDIN_FILENO and STDOUT_FILENO (from <unistd.h>). So I would venture you dont need any transformation.
EDIT: A bit unorthodox, but have you tried writing on STDOUT_FILE or reading STDIN_FILENO in your server? By very quickly glancing at the xinetd code, it looks like it just dup()s the open socket fd to all fds of the server. Maybe you can use either one as full duplex.
I only looked here
for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ )
{
if ( dup2( descriptor, fd ) == -1 )
{
msg_resume();
msg( LOG_ERR, func,
"dup2( %d, %d ) failed: %m", descriptor, fd ) ;
_exit( 1 ) ;
}
}

Related

Sending spoofed syslog messages in Perl

TL;DR I am trying to send syslog messages I have already created to a syslog server using spoofed source IPs but I'm making it really hard for myself and could do with a succinct approach
Most questions about syslog do not include the spoofed IP problem hence I am asking afresh.
I am writing (well updating) a script I wrote a long time ago that generates spoofed syslog messages (using UDP). It currently uses Net::RawIP which is terrible for portability and also the code for the transmission I wrote ages ago has decided to stop working in Perl 5 (I haven't used this for ages and I am refreshing it). I have been meaning to get rid of Net::RawIP for ages but its the only one I know how to use!
Given I have to fix it and I have a little time at the moment I probably want to move to use the Socket capability, which is what I have been playing with - using code from SO or gists or other places I can find - rather than something like IO::Socket as I need the spoofed IPs permission given a low level ability to write to sockets.
However, I have tied myself in knots with this, what I have right now forms the packets from scratch and then creates a socket and sends it, but in the processes wraps a superflous IPv4 header (I can see using wireshark) and without starting afresh I think its stuck like that as it has a fundamental flaw, hence I'm not sharing old code.
Basically, I can keep playing with the overly complicated code I have or ask for help simplify it, as I am beyond my knowledge of sockets and many hours of googling haven't helped much. What I keep finding is code that will work but it not compliant in some way - probably not an issue for what they are usually for which is for DDOS or syn attacks or whatever.
Key requirements of this are (which every attempt I have done has failed in some form!):
must come from a spoofed source IP and go to a known destination IP
(hence I'm using UDP) (both of which I have in config variables) so that the syslog server things many different devices generated the logs
must come from a set port and go to a set port (both of which I have in my
existing config variables)
must contain a message I have already formed which includes all the syslog content (the PRI and the syslog message content)
must be fully complaint with checksums and packet lengths etc when received
be as portable as possible (I'll probably embed it in my main script to keep it all in one file I can share with others).
I just feel there must be a simple and easy way to do this as everything I have is overly flexible and complicated and a nightmare to unwind.
NB This is shared in Sourceforge as "must syslog" and so you can see what I used to do but be aware its stopped working so it wont work if you run it currently! Once I fix this I'll upload a new version.
Cheers, --Chris
Actually I just had a breakthrough, I have linked the sources in the code but I found a test harness that is pretty basic and some UDP checksum code that with a bit of playing worked together and wireshark confirms its all correct
Posted in case someone else needs it as its taken me a good couple of days to get to this
#!/usr/bin/perl
use Socket;
use List::Util qw(sum);
sub udp_checksum {
# thanks to ikegami in post https://stackoverflow.com/questions/46181281/udp-checksum-function-in-perl
my $packed_src_addr = shift; # As 4-char string, e.g. as returned by inet_aton.
my $packed_dst_addr = shift; # As 4-char string, e.g. as returned by inet_aton.
my $udp_packet = shift; # UDP header and data as a string.
my $sum = sum(
IPPROTO_UDP,
length($udp_packet),
map({ unpack('n*', $_) }
$packed_src_addr,
$packed_dst_addr,
$udp_packet."\0", # Extra byte ignored if length($udp_packet) is even.
),
);
while (my $hi = $sum >> 16) {
$sum = ($sum & 0xFFFF) + $hi;
}
return ~$sum & 0xFFFF;
}
#this was found and adapted from http://rhosted.blogspot.com/2009/08/creating-udp-packetip-spoofing-through.html
$src_host = $ARGV[0];
$dst_host = $ARGV[1];
$src_port = 33333;
$dest_port = 514;
$cksum = 0; #initialise, we will sort this later
#$udp_len is the udp packet length in the udp header. Its just 8 plus the length of the data
#for this test harness we will set the data here too
$data = "<132> %FWSM-3-106010: Deny inbound tcp src outside:215.251.218.222/11839 dst inside:192.168.1.1/369";
$udp_len = 8+length($data);
$udp_proto = 17; #17 is the code for udp
#Prepare the udp packet, needed for the checksum to happen, then get the checksum (horrifically complicated, just google it)
$udp_packet = pack("nnnna*", $src_port,$dest_port,$udp_len, $cksum, $data);
$cksum = udp_checksum(inet_aton($src_host),inet_aton($dst_host),$udp_packet);
$zero_cksum = 0;
#test harness checks about host IPs
my $dst_host = (gethostbyname($dst_host))[4]; my $src_host = (gethostbyname($src_host))[4];
# Now lets construct the IP packet
my $ip_ver = 4;
my $ip_len = 5;
my $ip_ver_len = $ip_ver . $ip_len;
my $ip_tos = 00;
my ($ip_tot_len) = $udp_len + 20;
my $ip_frag_id = 19245;
my $ip_frag_flag = "010";
my $ip_frag_oset = "0000000000000";
my $ip_fl_fr = $ip_frag_flag . $ip_frag_oset;
my $ip_ttl = 30;
#H2H2nnB16C2na4a4 for the IP Header part#nnnna* for the UDP Header part.
#To understand these, see the manual of pack function and IP and UDP Header formats
#IP checksum ($zero_cksum is calculated by the kernel. Dont worry about it.)
my ($pkt) = pack('H2H2nnB16C2na4a4nnnna*',
$ip_ver_len,$ip_tos,$ip_tot_len,$ip_frag_id,
$ip_fl_fr,$ip_ttl,$udp_proto,$zero_cksum,$src_host,
$dst_host,$src_port,$dest_port,$udp_len, $cksum, $data);
#bit that makes the socket and sends the packet
socket(RAW, AF_INET, SOCK_RAW, 255) || die $!; setsockopt(RAW, 0, 1, 1);
my ($destination) = pack('Sna4x8', AF_INET, $dest_port, $dst_host);
send(RAW,$pkt,0,$destination);

TCP recv() function behavior in a loop in a program?

I have a TCP connection active with socket being created with TCP_KEEPALIVE parameter.
Now,
While(1)
{
int n = ::recv(socketId,buff,BUF_SIZE,MSG_WAITALL);
if ( n > 0)
{
// do something
}
}
Now lets say, if I don't receive data at socketId for sometime lets say 2-3 minutes ?
what will happen ? will the program keep waiting at recv() ?
While doing this, I observed that the my program stopped after some time when I stopped receiving data on the socket : socketId.
My program did not create any core dump file, No sign of crashing or anything.
So can someone explain why the program/process stopped ?
Impossible to say, as your progam is improperly written.
If n > 0, you received n bytes of data, and you can process it.
If n == 0, the peer has disconnected: you must close your socket and stop reading.
If n == -1, there was an error, and you should print it or log it, via errno, strerror(), or perror(), and then close the socket as above.

how to stop read() function?

I am writing an UDP client/server programs in C on linux. The thing is that I must add connection check feature. in linux man pages i found example of udp client with this feature( http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo.3.html ). It uses write/read functions to check server response. I tried to apply it to my program, and it looks like this:
char *test = "test";
nlen = strlen(test) + 1;
if (write(sock, test, nlen) != nlen) { // socket with the connection
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(sock, buf, nlen);
if (nread == -1) {
perror("Connection");
exit(EXIT_FAILURE);
}
the problem is than than i execute program with this bit when server is on, it does nothing except reading input infinite time which it doesn't use too. I tried kill(getpid(), SIGHUP) interrupt, which i found other similar topic here, and shutdown(sock, 1), but nothing seems to work. Could you please tell me a way out how to stop the input read or any other possible option to check if udp server is active?
You should use asynchronous reading.
For this you must use the select() function from "sys/socket.h".
The function monitors the socket descriptor for changes without blocking.
You can find the reference for it here or here or by typing "man select" in your console.
There is an example here for Windows, but its usage is very similar to UNIX.

Select and read sockets (Unix)

I have an intermittent problem with a telnet based server on Unix (the problem crops up on both AIX and Linux).
The server opens two sockets, one to a client telnet session, and one to a program running on the same machine as the server. The idea is that the data is passed through the server to and from this program.
The current setup has a loop using select to wait for a "read" file descriptor to become available, then uses select to wait for a "write" file descriptor to become available.
Then the program reads from the incoming file descriptor, then processes the data before writing to the outgoing descriptor.
The snippet below shows what is going on. The problem is that very occasionally the read fails, with errno being set to ECONNRESET or ETIMEDOUT. Neither of these are codes documented by read, so where are they coming from?
The real question is, how can I either stop this happening, or handle it gracefully?
Could doing two selects in a row be the problem?
The current handling behaviour is to shut down and restart. One point to note is that once this happens it normally happens three or four times, then clears up. The system load doesn't really seem to be that high (it's a big server).
if (select(8, &readset, NULL, NULL, NULL) < 0)
{
break;
}
if (select(8, NULL, &writeset, NULL, NULL) < 0)
{
break;
}
if (FD_ISSET(STDIN_FILENO, &readset)
&& FD_ISSET(fdout, &writeset))
{
if ((nread = read(STDIN_FILENO, buff, BUFFSIZE)) < 0)
{
/* This sometimes fails with errno =
ECONNRESET or ETIMEDOUT */
break;
}
}
Look at the comments in http://lxr.free-electrons.com/source/arch/mips/include/asm/errno.h on lines 85 and 98: these basically say there was a network connection reset or time out. Check and see if there are timeouts you can adjust on the remote network program, or send some periodic filler bytes to ensure that the connection stays awake consistently. You may just be victim of an error in the network transit path between the remote client and your local server (this happens to me when my DSL line hiccups).
EDIT: not sure what the downvote is for. The man page for read explicitly says:
Other errors may occur, depending on the object connected to fd.
The error is probably occuring in the select, not in the read: you're not checking errors after the select, you're just proceeding to the read, which will fail if the select returned an error. I'm betting if you check the errno value after the select call you'll see the errors: you don't need to wait for the read to see the errors.

How do I call a perl process that is already running from another script?

Problem:
scriptA.cgi is sitting in an infinite loop and handling an open socket to a Flash client.
scriptB.cgi is called from the web, does what it needs to do and then needs to inform scriptA to send a message to the client.
Is this possible? I'm stuck on how to have scriptB identify the instance of scriptA that is sitting there with the socket connection, rather than launching one of its own.
all thoughts appreciated.
If the communication needs are simple, this is a good application for signals.
Edited to store process id from scriptA and read it in scriptB -- scripts A and B have to agree on a name.
# script B
do_scriptB_job();
if (open(my $PID_FILE, "<", "scriptA.pid.file")) {
$process_id_for_scriptA = <$PID_FILE>;
close $PID_FILE;
kill 'USR1', $process_id_for_scriptA; # makes scriptA run the SIGUSR1 handler
}
# script A
open(my $PID_FILE, ">", "scriptA.pid.file");
print $PID_FILE $$;
close $PID_FILE;
my $signaled = 0;
$SIG{"USR1"} = \sub { $signaled = 1 } # simple SIGUSR1 handler, set a variable
while ( in_infinite_loop ) {
if ($signaled) {
# this block runs only if SIGUSR1 was received
# since last time this block was run
send_a_message_to_the_client();
$signaled = 0;
} else {
do_something_else();
}
}
unlink "scriptA.pid.file"; # cleanup
When script A receives a SIGUSR1 signal, the script will be interrupted to run the USR1 signal handler, setting $signaled. The thread of execution will then resume and the script can use the information.
Have scriptA store it's pid somwhere (in a db with some kind of id), then scriptB can look up the pid in the db and send a signal to scriptA.
Edit:
Answering question asked in comment
The pid of the process can be found using perls builtin variables $$ or $PID or $PROCESS_ID depending on how old your perl is.
See perlvar for details.
I hope this is the ID you where looking for. If not you'll have to find a way to separate the different scriptA instances. (Perhaps by session id, or socket. Here I cant help you further)
Other people have mentioned how to get the PID (if you didn't fork() it yourself, just have the other-process write it... somewhere... that both processes know how to get it. or walk the process table, but that's a horrible solution and completely unscalable beyond a singleton).
Since you note that any thoughts are welcome, note that perldoc perlipc explains a variety of mechanisms you might use for the actual communication:
NAME
perlipc - Perl interprocess communication (signals, fifos, pipes, safe
subprocesses, sockets, and semaphores)
DESCRIPTION
The basic IPC facilities of Perl are built out of the good old Unix
signals, named pipes, pipe opens, the Berkeley socket routines, and SysV
IPC calls. Each is used in slightly different situations.
Domain sockets: http://www.perl.com/doc/FMTEYEWTK/IPC/unix.html
?
I was tempted to answer, 'send signals' or 'use some kind of IPC to talk between apps' but, a far easier and scalable approach is to use a sqlite (or other) database that all scripts can talk to,
ScriptA.cgi would poll the database by doing something like 'SELECT event FROM events WHERE clientID=?'.
ScriptB.cgi would simply insert a row into the events table with the right clientID.
That avoids all of the 'find the pid' mess and also mean that you don't get the blocking IO problems you would get with named pipes or if one script crashed.