I spent about three hours today putting together a Quake2 scanner for
local area networks. Helps to find out when someone is playing Quake and
hasn't informed me.
This is my first attempt ever at programming under Linux, my first
attempt ever at network programming, and my first bit of C programming
in about three years. I'm elated.
~60 lines without the comments. The online version is at
www.ufies.org/~trion/qscan.c
--- qscan.c -----------------------------------------------------------
/*
* Quake2 scanner
*
* Copyright (C) 2000, Kiran Jonnalagadda <[EMAIL PROTECTED]>
* Licensed under the terms of the GNU General Public License
*
* Compile with "gcc qscan.c -o qscan" and copy the output file to
* /usr/local/bin/ or wherever you prefer.
*
* To use, execute it without any arguments. qscan will broadcast
* to the local network and wait for 5 seconds to see if any Quake2
* server responds. If any servers are found, qscan will generate
* output in this format:
* "Quake: servername MAPNAME current-users / allowed-users"
*
* Note: This is my first attempt at programming under Linux, and my
* my first attempt at socket level network programming too. I know
* this program is primitive and not the least bit user-friendly,
* but it serves my needs. Still, I'd like to hear from you if you
* have any suggestions for improving it.
*
* Here is how I use this program:
*
* I have this line in my crontab (crontab -e to edit):
* * /5 * * * * /usr/local/bin/qscan >> /home/jace/.tickastat
* (Note: There's no space between '*' and '/5' above. I needed to add
that
* to avoid closing this comment)
*
* The '.tickastat' file is setup to be monitored by the Tick-A-Stat
panel
* applet for GNOME. qscan executes out of crontab every five minutes.
If
* a Quake server is found, I get a ticker message on my panel naming
the
* server and the number of users currently on it. There is no output if
* no servers are found.
*
* You might also want to look at www.ufies.org/~trion/xmms-ticker.html
for
* another quick hack related to Tick-A-Stat. The applet itself can be
* found at www.gnome.org. I got it as part of the gnome-applets 1.1.4
* package.
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
/* This handler bails us out after 5 seconds */
static void alarm_handler (int signo)
{
exit (0);
}
/* Start of program execution */
int main()
{
/* Define the variables we will be using. The contents of the
broadcast_packet variable are based on the contents of a
packet captured using a packet sniffer (tcpdump). The data
is exactly 11 bytes in size. The response is usually 41 bytes,
but we'll use a larger buffer just to play safe.
*/
int sockfd;
const int on = 1;
struct sockaddr_in address;
struct sockaddr preply_addr;
int result;
char *broadcast_packet = "\xFF\xFF\xFF\xFFinfo 34";
char response[50];
int addr_len = sizeof(preply_addr);
int recvlen;
/* Initialise the socket for sending out a broadcast.
SOCK_DGRAM indicates a datagram protocol, or UDP.
We would use SOCK_STREAM for TCP.
*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("255.255.255.255");
address.sin_port = htons(27910);
/* Clarify that we really want to do a broadcast and that this isn't
a mistake. The socket system makes this necessary just in case
we're a program that takes an IP address at the command line and
the user fooled us into making a broadcast.
*/
setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
/* Broadcast now. Any Quake2 servers that receive this will reply
with a 41 byte UDP packet.
*/
result = sendto (sockfd, (void *) broadcast_packet, 11, 0,
(struct sockaddr *) &address, sizeof(address));
/* Abort with an error message if the broadcast didn't work */
if (result == -1) {
perror ("qscan");
exit(1);
}
/* Setup the handler that will bail us out after the timeout */
signal (SIGALRM, alarm_handler);
/* Tell the system to raise the ALRM signal after 5 seconds */
alarm (5);
/* Loop continously listening for responses to the broadcast from
any servers on the local network. The ALRM signal at the end of
5 seconds will bail us out.
*/
for (;;)
{
/* recvfrom is a blocking call for UDP data. We need to listen on
the
same port that we broadcasted from, hence the "sockfd" from the
original broadcast.
*/
if ((recvlen = recvfrom (sockfd, response, sizeof (response), 0,
&preply_addr, &addr_len)) > 0)
{
/* We got a reply. This bit of code patches the packet contents
slightly to create printable text. Use a packet sniffer if
you
want to see what the packet really contains. tcpdump won't
work
here -- it loses the last few bytes. Try ethereal instead.
*/
response[recvlen-1] = '\0';
printf ("Quake: %s\n", &response[12]);
}
}
/* Execution never reaches here. Program termination is handled by
the
alarm_handler function.
*/
}
--- qscan.c -----------------------------------------------------------
My Netscape is set to wrap at 72 columns, so some lines above might have
wrapped around. Use the online version if this is causing you any
problem.
--
Kiran Jonnalagadda
http://lunateks.com
baby.sh: while true; do echo "^G^G^G^G^G"; sed -e 's/food/poop/'; sync;
sync; sleep 15; done
To subscribe / unsubscribe goto the site www.ilug-bom.org ., click on the mailing list
button and fill the appropriate information
and submit. For any other queries contact the ML maintener