In examining hotline X and output from OT Session Watcher I was able to create a unix program which opened a SOCK_STREAM (stream socket) and connected to a hotline server. Initially I thought it might be possible to open 100 or so streams to a server, but only 5 are permitted from the same client. Anyway here is the connection sequence: (from the clients perspective)
Send 12 bytes: 54 52 54 50 48 4F 54 4C 00 01 00 02
Recieve 8 bytes: 54 52 54 50 00 00 00 00
Send 41 bytes: 00 00 00 6B 00 00 00 01 00 00 00 00 00 00 00 15 00 00 00 15 00 02 00 66 00 09 48 4C 5F 53 6F 63 6B 65 74 00 68 00 02 00 9D
Send 22 bytes: 00 00 01 2C 00 00 00 02 00 00 00 00 00 00 00 02 00 00 00 02 00 00
Send 22 bytes: 00 00 00 65 00 00 00 03 00 00 00 00 00 00 00 02 00 00 00 02 00 00
Recieve 22 bytes: 00 01 00 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 02 00 00
Recieve X bytes: List of users on server (in hex).
Recieve news/agreement. (Can be ignored)
That is the full login sequence, of course with that sequence you will get logged into the server as "HL_Socket", the second send tells the server what nick to login with.
The following program "hotline_socket.cpp" is included in this file:
------Cut here------
/*
* This program logs into a hotline server and posts a news message.
* It is not meant to bomb servers, though it could easily be modified to
* do so. It simply demonstrates the login sequence for the hotline
* server.
*
* Special thanx to Ballbach and Matt.
*
* [email protected]
*
* Tested under Linux. The default port number for hotline servers is 5500
* To compile: g++ hotline_socket.cpp
* To use: a.out <host> <port-number>
*
*/
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/time.h>
main(int argc, char *argv[])
{
int sock_fd;
struct sockaddr_in dest_addr;
struct hostent *he;
char buf[8];
char users[100000];
char tmp[22];
int i;
char *login_seq =
"\x00\x00\x00\x6B\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00"
"\x15\x00\x02\x00\x66\x00\x09\x48\x4C\x5F\x53\x6F\x63\x6B\x65\x74\x00\x68\x00"
"\x02\x00\x9D/";
char *login_seq2 =
"\x00\x00\x01\x2C\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00"
"\x02\x00\x00/";
char *login_seq3 =
"\x00\x00\x00\x65\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00"
"\x02\x00\x00/";
char *news_post =
"\x00\x00\x00\x67\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00"
"\x2C\x00\x01\x00\x65\x00\x26\x59\x6F\x75\x20\x68\x61\x76\x65\x20\x62\x65\x65"
"\x6E\x20\x68\x61\x78\x4F\x72\x65\x64\x20\x62\x79\x20\x61\x20\x53\x4F\x43\x4B"
"\x5F\x53\x54\x52\x45\x41\x4D/";
/* To send a chat message, the first \x67 should be \x69 */
if (argc != 3) {
cout << "Usage: " << argv[0] << " <hostname> <port-number>\n";
exit(1);
}
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
cout << "Unknown host.\n";
exit(1);
}
dest_addr.sin_family = AF_INET;
i = atoi(argv[2]);
dest_addr.sin_port = htons(i);
dest_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(dest_addr.sin_zero), 8);
if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
cout << "Cannot open socket.\n";
exit(1);
}
if(connect(sock_fd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) == -1) {
cout << "Could not connect to socket.\n";
exit(1);
}
/* Send the initial TRTPHOTL\0\1\0\2 and recieve TRTP\0\0\0 */
send(sock_fd, "TRTPHOTL\0\1\0\2", 12, 0);
recv(sock_fd, buf, 8, 0);
send(sock_fd, login_seq, 41, 0); /*Send nick, login...*/
send(sock_fd, login_seq2, 22, 0);
send(sock_fd, login_seq3, 22, 0);
recv(sock_fd, tmp, 22, 0);
recv(sock_fd, users, 100000, 0);
/* If the # of users on the server > one hundred thousand bytes then this
* will not work */
/* Ok now we are logged in */
cout << "Posting to news...\n";
send(sock_fd, news_post, 64, 0);
recv(sock_fd, tmp, 22, 0);
/*Fuck all the recvs we should be doing here and quit :) */
close(sock_fd);
exit(0);
}