|
Author |
Topic:
Quantumlink protocol not that hard... (Read 82
times) |
Keith
Henrickson Guest
|
|
Quantumlink protocol not that
hard... « Thread Started on
7/3/05 at 14:38 » |
|
I've
actually got a good deal of the protocol understood. My
challenge is finding the time to do anything with
it.
One challenge to be overcome is understanding
the disk file format. There are only 3 'real' programs
on the disk. "*", "CHANGE ACCESS", and "DSK". The
remaining programs are all loaded through the three
letter filenames, as has been discussed on other
threads. These files are simply track/sector pointers to
the real files to be loaded. However, you ONLY have to
learn about this if you want to write your own BASIC
games to run inside people connection. Since each file
has a header saying what to do with it, and can be
lightly compressed/encrypted, this would need some
exploration.
However, most people are probably
interested in bringing back the service. It's not THAT
hard to get your head around the protocol.
The
Tymnet/Telenet login stuff is EASY to fake. Simply send
the following string. C format for any programmers out
there. "IDENTIFIER\xBA\xBA+" That's it. Just use a phone
number like "/555-5555" to use the Tymnet (I beleive)
login. Don't worry about what the commands mean. It's
useless once you get connected.
Next comes layer
2. The client will send
"\x5a\x4*\x*1\x4*\x*1\x7F\x7F\x23\x07\x09\x0D" The 5A
and the 0D are framing characters. They were used by the
system to pick each packet apart. The stuff with the '*'
is the CRC. It is NOT a custom CRC, it is plain jane
CRC-16, padded with the 4's and the 1's. Why they did
THAT, I have no clue. The next two bytes are sequence
numbers. The first byte is the packet # that is being
transmitted. The second byte is the last packet number
successfully received by the sender of the packet. It
ALWAYS starts at 0x7F, and wraps around to 0x10. For
instance, if I am sending packet 0x15, and I have most
recently received your packet 0x11, then the bytes would
be "\x15\x11". This way every time you receive a packet,
you know which of YOUR packets the other guy has
received so that you can throw away the copies you kept
and free up memory. The "\x23\x07\x09" is saying, "I am
a confused client, and my version number is
9.7."
To respond to this, the server sends back
"\x5A\x4*\x*1\x4*\x*1\x7F\x7F\x24\x0D". The "\x24" tells
the client, "You're OK. I understand you, and we'll
start all over."
For those of you who have worked
at VERY low levels with ISDN, you will recognize some of
this from Q.921. Interesting. Of course, all the numbers
have changed and stuff, and the CRCs are added. But the
concept is the same. LAPM on modems is actually quite
similar too. Again, in ISDN terms, "\x23" is like a
SABME, and "\x24" is like a UA.
Once you exchange
these two packets, layer 2 is up. YAY. The client will
switch from "Waiting for access to Q-Link..." to
"Verifying your account details".
It will then
send a packet like.
"\x5A\x4*\x*1\x4*\x*1\x10\x7F\x20DD1234567890ABCD\x0d"
Ok,
now "\x20" says that this is a data packet. Data
packets, and ONLY data packets increment our packet
number. That's why the "\x7F" changed to a "\x10". Yay.
Now, the next two bytes are always two alphanumerics.
That is the command the client is sending. "DD" means,
"logging in with account number and validation code".
The first ten digits are your account number, NOT your
screen name. The screen name is NEVER sent to the
server. The last four letters are a validation code.
Sort of a password.
If your account is valid, the
server will respond "D3EFGH". D3 says to write a new
validation code, and the new code, which will be used on
the NEXT login, is "EFGH".
When the client has
done so, it will send "D6", saying it wrote the code
without errors.
The server will then send either
a "DO", to display the main menu, or it will send the
welcome text using "SM/SE". All lines but the last are
sent with SM, and the last line is sent with SE. That
way the client knows you have the whole thing, and lets
you press F5 to go to the main menu.
I know a LOT
more, and if there is real interest I will write it
up.
|
|
Logged | | |
Keith
Henrickson Guest
|
|
Re: Quantumlink protocol not that
hard... « Reply #1 on 7/3/05
at 14:44 » |
|
Oh, and if
you want to send me an email, my address is
flipper@phin.com
|
|
Logged | | |
Jeff
Ledger Administrator
member is offline
Joined: Feb 2004 Posts:
182
|
|
Re: Quantumlink protocol not that
hard... « Reply #2 on 7/3/05
at 21:43 » |
|
The only
successful login I've been able to use is
the TERMINAL= @ @ \0d CONNECTED
using
the number +5551212
Once connected it sends about
5 of these and then gives
up.
ZqE±N# ZqE±N# ZqE±N# ZqE±N#
Am
I looking at some type of compressed
code?
Jeff
|
|
Logged |
"My computer boots in 2 seconds!" --Microsoft
Beat That! | |
Keith
Henrickson Guest
|
|
Re: Quantumlink protocol not that
hard... « Reply #3 on 7/4/05
at 0:39 » |
|
Ok, so
you're having better luck with Telenet. Or I have them
backwards. Been MANY years, and I never used either
service for anything but Q-Link.
ANYWAY, you're
seeing the clients hellos.
Z is 0x5A in ASCII, of course, and will
start EVERY packet.
The next four characters are
the encoded CRC. Looking them up in an ASCII table, I
get: 0x71, 0x45, 0xF1, 0x4E. The significant
digits are 7, 5, F, E. The others are the static padding
I referred to (if incorrectly), in my original post. The
CRC is reassembled as FE75. This seems to be a perfectly
normal CRC-16 of the remaining bytes in the
packet.
The '#' is 0x23 in ASCII, and therefore
this is the 'confused client' packet that is always sent
on startup.
The remaining bytes 0x7F, 0x7F, 0x07,
0x09 (the last two may differ, they're a version
number), are unprintable and therefore won't show in a
simple ASCII trace.
You're 90% of the way to your
first breakthrough. If you can figure out how to
calculate CRCs (test it by confirming the CRC in the
0x23. I SWEAR this is a normal CRC-16.), then you can
reply by changing the 0x23 to a 0x24, getting rid of the
0x07 and 0x09 bytes, fixing up the CRC, and sending it
to the client.
You will see your first text
change when you get it right. The CRC function is based
on a very poor understanding of what it was doing. It
works, but all the variable names should be considered
wrong. The algorithm is poor as well. I have a better
function, but haven't had a chance to test it yet. I
beleive this function generates CRC-16 with the byte
order incorrect, which will of course, propogate through
the entire CRC function
/*Compute CRC for a
packet. The packet data including sequence numbers
and the packet type must be present. The framing
characters and CRC bytes should not be present at
all. */ unsigned short compute_CRC(unsigned char
*pszPacketDataBuf, int nPacketLen){
int
nByteCounter; int nBitCounter; unsigned short
nTempCRC; unsigned char nCRCHigh; unsigned char
nCRCLow;
nCRCHigh = 0; nCRCLow = 0;
for
(nByteCounter = 0; nByteCounter < nPacketLen;
nByteCounter++){ /*Set a counter to 8
times*/ nTempCRC = (nCRCLow << 8); for
(nBitCounter = 0; nBitCounter < 8; nBitCounter++)
{ /*Move low bit of new byte to C, high bit of new
byte becomes 0 Move C into low bit of A, Move high
bit of A into C Mask off all of A except new bit
*/ nTempCRC = ((nTempCRC & 0xFF00) |
((pszPacketDataBuf[nByteCounter] & (1 <<
nBitCounter)) >> nBitCounter)); /*Xor CRChigh
into A*/ nTempCRC = nTempCRC ^ nCRCHigh; /*Move
low bit of CRClow into C, high bit of CRC low becomes
0 Move C into high bit of A, move low bit of A into
C If C is not set, not ready to xor in CRC polynomial
*/ if (nTempCRC & 1) { nTempCRC = nTempCRC
>> 1; /*Get CRClow Xor in polylow Store
CRClow */ nTempCRC = ((nTempCRC & 0x00FF) |
(((nTempCRC >> 8) ^ 0xA0) << 8)); /*Xor
in polyhigh Store CRChigh */ nTempCRC = nTempCRC ^
0x01; nCRCHigh = nTempCRC & 0x00FF; } else
{ nTempCRC = nTempCRC >> 1; nCRCHigh =
nTempCRC & 0x00FF; } } nCRCLow = nTempCRC
>> 8; } return ((nCRCHigh << 8) |
nCRCLow); }
/*Takes some data and sends it
through the packet protocol. The packet type byte
must be present, but the sequence numbers and framing
bytes will be generated by this function. */ void
transmit_packet(unsigned char *pPacketBuf, int
nPacketLen) { unsigned char
szTempBuf[1024]; unsigned short
nCRC;
szTempBuf[0] =
0x5A;
memcpy(&szTempBuf[7], pPacketBuf,
nPacketLen); szTempBuf[5] = 0x7f; szTempBuf[6] =
0x7f; nCRC = compute_CRC(&szTempBuf[5],
nPacketLen+2); szTempBuf[1] = (nCRC & 0x00F0) |
0x01; szTempBuf[2] = (nCRC & 0x000F) |
0x40; szTempBuf[3] = ((nCRC >> 8)& 0x00F0)
| 0x01; szTempBuf[4] = ((nCRC >> 8)&
0x000F) | 0x40; szTempBuf[nPacketLen + 7] =
0x0D;
write(nWriteFD, szTempBuf, nPacketLen +
8); }
// Of course, this isn't in a function,
but it shows the way to invoke the above code to get
what you want transmit_packet("\x24",1);
|
|
Logged | | |
Jim
Brain Full Member
member is online
Joined: Mar 2004 Posts:
189
|
|
Re: Quantumlink protocol not that
hard... « Reply #4 on 7/23/05
at 2:28 » |
|
Yay!
Success,
thanks to Keith:
2005-07-23
01:15:42:168113080::RS->|0000|0d 0a |..
| 2005-07-23 01:15:42:168113080::RS->|0000|43 4f
4e 4e 45 43 54 |CONNECT | 2005-07-23
01:15:42:168113080::RS->|0000|0d 0a |..
| 2005-07-23 01:15:43:168113080::RS<-|0000|0d |.
| 2005-07-23 01:15:43:168113080::RS<-|0000|0d |.
| 2005-07-23 01:15:43:168113464::RS->|0000|54 45
52 4d 49 4e 41 4c 3d 0d |TERMINAL=. | 2005-07-23
01:15:47:168113080::RS<-|0000|44 31 0d |D1.
| 2005-07-23 01:15:47:168113464::RS->|0000|40 |@
| 2005-07-23 01:15:47:168113080::RS<-|0000|53 45
54 3f 20 31 30 3a |SET? 10: | 2005-07-23
01:15:48:168113080::RS<-|0000|30 2c 31 35 3a 30 2c 30
|0,15:0,0 | 2005-07-23
01:15:48:168113080::RS<-|0000|3a 33 33 2c 35 37 3a 31
|:33,57:1 | 2005-07-23
01:15:48:168113080::RS<-|0000|2c 36 33 3a 30 0d
|,63:0. | 2005-07-23
01:15:48:168113464::RS->|0000|40 |@ | 2005-07-23
01:15:49:168113080::RS<-|0000|43 4f 4e 4e 45 43 54 20
|CONNECT | 2005-07-23
01:15:49:168113080::RS<-|0000|37 30 33 33 39 2e 38 37
|70339.87 | 2005-07-23
01:15:50:168113080::RS<-|0000|0d |. | 2005-07-23
01:15:51:168113464::RS->|0000|0d 0d 43 4f 4e 4e 45 43
54 45 44 0d |..CONNECTED. | 2005-07-23
01:15:54:168113080::RS<-|0000|5a 81 42 31 4e 7f 7f 23
|Z.B1N..# | 2005-07-23
01:15:54:168113080::RS<-|0000|05 09 0d |...
| 2005-07-23 01:15:54:168113464::RS->|0000|5a f1
43 11 41 7f 7f 24 0d |Z.C.A..$. | 2005-07-23
01:15:55:168113080::RS<-|0000|5a 71 4b 41 4f 10 7f 20
|ZqKAO.. | 2005-07-23
01:15:55:168113080::RS<-|0000|44 44 35 38 38 39 33 34
|DD588934 | 2005-07-23
01:15:55:168113080::RS<-|0000|39 35 36 37 31 20 20 20
|95671 | 2005-07-23
01:15:56:168113080::RS<-|0000|0d |. | 2005-07-23
01:15:56:168113464::RS->|0000|5a 61 40 f1 41 10 10 20
44 33 31 20 20 20 0d |Za@.A.. D31 . | 2005-07-23
01:15:56:168113080::RS<-|0000|5a c1 44 81 45 11 10 20
|Z.D.E.. | 2005-07-23
01:15:57:168113080::RS<-|0000|53 53 0d |SS.
| 2005-07-23 01:15:57:168113464::RS->|0000|5a 31
48 81 44 11 11 20 53 53 0d |Z1H.D.. SS. | 2005-07-23
01:15:59:168113080::RS<-|0000|5a 31 47 c1 40 12 11 20
|Z1G.@.. | 2005-07-23
01:15:59:168113080::RS<-|0000|53 47 0d 5a 21 43 31 42
|SG.Z!C1B | 2005-07-23
01:16:00:168113080::RS<-|0000|13 11 20 44 36 0d |..
D6. | 2005-07-23 01:16:00:168113464::RS->|0000|5a
b1 49 c1 4f 12 13 20 44 4f 0d |Z.I.O.. DO.
|
I'm at the 9 colored blocks... I never
used Q-Link, so I am driving in the blind.
Notice
in the above that I got a SS after the D3, to which I
sent an SS back. I then got a SG and a D6 piggybacked on
it, to which I sent the DO.
In any event, many
thanks. If I had not taken such a wrong turn trying to
step through the code (spent days trying to get through
it), I'd be much further. Oh well, time to make up for
lost time.
Keith, you sure I can;t interest you
in a Java codebase? It has the FSM already installed
(though it will no doubt need serious
work).
Jim
|
|
Logged |
-- Jim Brain
| |
Jim
Brain Full Member
member is online
Joined: Mar 2004 Posts:
189
|
|
Re: Quantumlink protocol not that
hard... « Reply #5 on 7/23/05
at 2:31 » |
|
By the way,
here's a much simpler CRC to use:
Code:
int poly=0xa001; int crc=0; int
data; boolean carry;
for(int
i=0;i<stream.length;i++)
{ data=stream[i]; for(int k=0;k<8;k++)
{ carry crc=crc^(data&1); data=data>>1;
if((crc&1)!=0)
{ crc=crc>>1; crc=crc^poly; }
else
{ crc=crc>>1; } } }
| |
|
« Last Edit:
7/23/05 at 2:36 by Jim
Brain » |
Logged |
-- Jim Brain
| |
Jim
Brain Full Member
member is online
Joined: Mar 2004 Posts:
189
|
|
Re: Quantumlink protocol not that
hard... « Reply #6 on 7/23/05
at 2:55 » |
|
OK, two
questions:
When I select All but Commodore
Showcase and PeopleConnection, I get ML, but what do I
need to send back?
Also, how does the server
determine which of them the user selected, since they
all send
ML?
|
|
Logged |
-- Jim Brain
| |
Keith
Henrickson Guest
|
|
Re: Quantumlink protocol not that
hard... « Reply #7 on 7/23/05
at 12:21 » |
|
People
connection sends MR, and of course does it's own thing.
To bring up the simplest of people connection screens,
send back 'CMLobby' and 'CE\x01JBrain'. It's not much,
but you will have access to the menu on F7 and
everything.
The other 8 areas should all function
identically. You should receive 'ML', and send back
'MC'. You will then see the first line of a menu pop up
at the top of the screen. It is waiting for the menu in
the form of 'KA' and 'KB' commands. To see how to draw a
menu, look at qlinkold/qmenus.c
The function
qmens_rendermenu() outputs a standard menu. There are
basically two fields to each line. One is the item
number. It simply says which item will be requested from
the server. The other field is a 24 bit value, of
which two bytes have a significance that I understand.
The first byte is the type of resource being requested.
Some of them are simple like, "Change Area Menu", or
"Post Office", or "Text Document". Some of them are
complicated, like "Gateway service", and "Message
Board", or "Mall Item". I have a list of what I know of
each item in qlinkold/qlinkfuncs.txt The second byte
is a bitfield, with the second bit indicating plus time
or not. IIRC. There is a buffer overflow here that lets
you create 'minus time'. Of course, that was just a
cosmetic indicator on the client side. Setting it didn't
do anything to the server.
One correction to
qlinkfuncs.txt is: Item 0x85 is the 'gateway
service', and basically a simple line by line terminal
program that communicates over the Y* series of commands
in that
file.
|
|
Logged | | |
Keith
Henrickson Guest
|
|
Re: Quantumlink protocol not that
hard... « Reply #8 on 7/23/05
at 14:02 » |
|
7/23/05
at 12:21, Keith Henrickson wrote:
The other 8
areas should all function identically. You
should receive 'ML', and send back 'MC'. You
will then see the first line of a menu pop up at
the top of the screen. It is waiting for the
menu in the form of 'KA' and 'KB' commands. To
see how to draw a menu, look at
qlinkold/qmenus.c
| | Also,
the client will send 'K1@@@a' or somesuch. There is a
hard coded list of these in the client, one for each of
the 8 root menus. After that, you're pretty much free to
pick your own menu names. THere are some rules, but I
haven't figured out what they are. The menu names are a
4 ASCII char encoding of a 24 bit number. But message
boards will pick their own 24 bit numbers in some cases.
I never did figure them out.
|
|
Logged | | |
| |