Orbited Internals..

0 views
Skip to first unread message

Niklas B

unread,
Mar 20, 2009, 5:32:30 AM3/20/09
to Orbited Discussion
Hi,

I have a challenge; I am writing an IRC client and if 10 users connect
to the irc server via Orbited, they all have the same IP (orbited's).
To counter this, there is a feature called CGI:IRC IP replacements
(implemented in several IRC deamons). It works like this:

1. Application (orbited, cgiirc) opens a connection
2. The app, before sending the nickname/ident with the user sends the
IP as password argument, i.e we send our real IP as password to the
server ("PASS 192.168.1.10")
3. The server takes the PASS argument, and set's it as the clients IP
internally (security by IP, i.e only orbited IP is allowed to send the
PASS argument)

This is great for applications such as CGI:IRC since ir's a perl
script that parses the IRC commands. However, orbited is fully
transparent. That means to implement this I would need javascript to
send the PASS command, which can't be trusted, a user could simply
send his own PASS command with any IP he see fits.

This means I have to modify orbited to send the PASS argument. This
ofcourse, is bad. I don't like changing the core (for updates and
such) but I see no other way really. Here is what I was thinking:

1. When orbited registers a new connection and opens a connection
to the IRC server it automatically sends the pass command.

But I am not sure where I would place this, and also how to get the
users IP. I was thinking about adding a send command in connectionMade
in proxy.py, similar to:

self.outgoingConn.transport.write('PASS ' + user_ip)

Am I missing something here?

Regards,
Niklas

Michael Carter

unread,
Mar 20, 2009, 6:00:12 AM3/20/09
to orbite...@googlegroups.com
Hey Niklas,


This means I have to modify orbited to send the PASS argument. This
ofcourse, is bad. I don't like changing the core (for updates and
such) but I see no other way really. Here is what I was thinking:

  1. When orbited registers a new connection and opens a connection
to the IRC server it automatically sends the pass command.

But I am not sure where I would place this, and also how to get the
users IP. I was thinking about adding a send command in connectionMade
in proxy.py, similar to:

   self.outgoingConn.transport.write('PASS ' + user_ip)

Am I missing something here?

You have set forth an interesting problem -- I have an idea on how we can solve it:

Add something to the TCPSocket API that allows us to inject the browser's ip address into the stream as needed. For instance:

conn = new Orbited.TCPSocket()
conn.open(...)
...
conn.write('PASS ' + Orbited.TCPSocket.insertions.MY_IP + '\n')

Where MY_IP causes a special frame to be sent to the server, which in turn injects the clients ip address into the stream.

I'm not sure about that api though -- We might be forced to not allow you to put the MY_IP constant directly into the write command, and instead do something like this:

conn.write("PASS ")
conn.insert(Orbited.TCPSocket.insertions.MY_IP)
conn.write("\n")

What do other people think?

-Michael Carter

Michael Carter

unread,
Mar 20, 2009, 6:08:38 AM3/20/09
to orbite...@googlegroups.com

You have set forth an interesting problem -- I have an idea on how we can solve it:

Add something to the TCPSocket API that allows us to inject the browser's ip address into the stream as needed. For instance:

conn = new Orbited.TCPSocket()
conn.open(...)
...
conn.write('PASS ' + Orbited.TCPSocket.insertions.MY_IP + '\n')

Where MY_IP causes a special frame to be sent to the server, which in turn injects the clients ip address into the stream.

I'm not sure about that api though -- We might be forced to not allow you to put the MY_IP constant directly into the write command, and instead do something like this:

conn.write("PASS ")
conn.insert(Orbited.TCPSocket.insertions.MY_IP)
conn.write("\n")

What do other people think?

Clearly this doesn't solve your security requirement.

I would further say we would need an [insertions] section in the config that dictate when insertions are allowed/required. For instance, we could have rules that specifiy that MY_IP is required after the 5 byte. Or required before the first \n, or something.

This does beg the question as to whether or not we even want to expose insertions client-side, as we could put enough information into the [insertions] config to have orbited automatically insert values.


-Michael Carter
 

-Michael Carter

Niklas B

unread,
Mar 20, 2009, 6:54:22 AM3/20/09
to Orbited Discussion
Agreed, it's a though one. Preferbly we would use an entirely server-
side solution (due to security) since we want orbibited to send this
_before_ a malicous user could send it themselves. But I am not to
happy to modify the orbited core. I should look up where the
connection is initated in the python code..

Niklas B

unread,
Mar 20, 2009, 7:05:05 AM3/20/09
to Orbited Discussion
So far I got this in proxy.py:97, function
outgoingConnectionEstablished:

self.outgoingConn.transport.write("PASS abc\n")

And it works like a charm. And since IRCd's only accept it one time,
it doesn't matter if a malicous user sends it again, it simply rejects
the second attempt:

[8603:7 65] <- connection 5: 'PASS abc'.
[8603:7 65] Connection 5: got PASS command (RFC 1459) ...
[8603:7 65] Connection 5: 10 bytes left in read buffer.
[8603:7 65] <- connection 5: 'PASS abc2'.
[8603:7 65] -> connection 5: ':irc.the.net 462 * :Connection
already registered'.

This should go for all IRCd. Now I just need to get our users IP

Niklas B

unread,
Mar 20, 2009, 7:13:49 AM3/20/09
to Orbited Discussion
Does anyone see any major issues with this solution.

Proxy.py:

In dataReceived(), after:

self.logger.access('new connection from %s:%s to %s:%d' %
(peer.host, peer.port, host, port))

We make sure we save our clients IP in self:

self.host = peer.host

Then, in outgoingConnectionEstablished, I do this:

self.outgoingConn.transport.write("PASS " + self.host + "\n")

That should solve my problems. Unless any of you sees any memory leaks
or something here?

If this works, I could probably supple a patch to make orbited IRC
support CGI:IRC modules. I was thinking:

In orbited.conf, have a cgiirc key that can be true or false. In
proxy.py we check if it's true or false when we register the
connection. If it's true, we save our IP. Then in
outgoingConnectionEstablished, if it's true, send it using PASS.

Jacob Rus

unread,
Mar 20, 2009, 1:23:55 PM3/20/09
to orbite...@googlegroups.com
Niklas B wrote:
> I have a challenge; I am writing an IRC client and if 10 users connect
> to the irc server via Orbited, they all have the same IP (orbited's).
> To counter this, there is a feature called CGI:IRC IP replacements
> (implemented in several IRC deamons). [...]

>
> This is great for applications such as CGI:IRC since ir's a perl
> script that parses the IRC commands. However, orbited is fully
> transparent. [...]

>
> This means I have to modify orbited to send the PASS argument. This
> ofcourse, is bad. I don't like changing the core (for updates and
> such) but I see no other way really.

Why don't you just have the users connect to some server in between
Orbited and the IRC server, basically another simple proxy, that just
injects that info? If we try to solve this via Michael's method, I
don't see that anything stops the user from still just sending
whatever IP they want, and not using the special injection call.

It strikes me that patching Orbited to "support" CGI:IRC is the wrong way to go.

–Jacob

Mario Balibrera

unread,
Mar 20, 2009, 5:22:31 PM3/20/09
to orbite...@googlegroups.com
Hello all. I agree with Jacob that this is beyond the scope of the project. However, proxy.py already keeps track of the incoming ip (line 61), and I think this information should be relayed to the client as part of the handshake. This won't solve your security issue, but it will at least make the type of application you describe possible. Thoughts?

Mario Balibrera
Reply all
Reply to author
Forward
0 new messages