Code Monkey home page Code Monkey logo

irc-idler's Introduction

Travis CI Build Status Go Report Card

DEPRECATED

IRC Idler is unmaintained and deprecated in favor of sandstorm-znc:

https://github.com/zenhack/sandstorm-znc

Please use that instead; I'll leave this here for posterity.


IRC Idler is a program which idles in IRC for you. Sandstorm will be the preferred way of running it, though it will work in traditional environments as well.

This is very much a work in progress. I'm currently dogfooding the sandstorm version, but it's not exactly polished.

Why

Lots of folks prefer to be persistently online on IRC. A common solution to this is to be logged in via a console IRC client on a server somewhere, running in tmux or GNU screen. This works, but is less than ideal.

What

IRC Idler connects to the IRC server for you, and then acts as an IRC server itself -- you connect to IRC Idler, and it proxies the connection. When you disconnect, it stays connected, and flags you as away until you reconnect, at which point it replays any messages you missed while you were gone.

Sandstorm Design Notes

IRC isn't a web-app so building a sandstorm app that offers it is slightly more complicated. We still want leverage sandstorm for authentication and authorization. We do this by listening on a websocket instead of a raw TCP port, and have users use websocket-proxy to connect. This scheme also translates decently to the non-sandstorm case.

On sandstorm, each IRC connection runs in its own grain. The websocket trick means we don't need to allocate a separate port to each network.

Building

The sandstorm version is in cmd/sandstorm-irc-idler, the non-sandstorm version is in cmd/irc-idler. Either executable can be built via standard go build.

Note that we link in sqlite3 via CGO. This makes cross-compilation non-trivial, so we do our sandstorm builds in the vagrant vm like everybody else. During these builds GOPATH is set to ${srcdir}/.sandstorm/gopath -- bear this in mind, as it won't look in your host's GOPATH for packages.

Using (sandstorm)

To use the sandstorm version, you must be an administrator for your sandstorm installation. This is because IRC Idler requires raw network access, which only an administrator can grant.

Each irc network you want to connect to must run in its own grain. To set up a new network:

  • Create a new IRC Idler grain

  • Fill out the settings for the IRC server on IRC Idler's web interface. For example, to connect to freenode, you would supply:

    • Host: irc.freenode.net
    • Port: 6667 for unencrypted, 6697 for TLS
    • Check the TLS box or not, depending on whether you want to use it (recommended).
  • Click on the "Request Network Access" button, and grant network access in the dialog that sandstorm presents

  • You will be presented with a websocket URL you can use to connect. You can get a traditional IRC client to connect to this by using websocket-proxy:

    websocket-proxy -listen :6000 -url ${websocket_url}
    

...and then pointing your IRC client at localhost port 6000.

Using (non-sandstorm)

As an example, to connect to Freenode via TLS:

./irc-idler -tls -raddr irc.freenode.net:6697 -laddr :6667

Then, point your irc client at port 6667 on the host running irc-idler.

Note well: irc-idler does not support accepting client connections via TLS, and it preforms no authentication. As a consequence, you should run it on a trusted network. One solution is to have it only listening on localhost on the server that's running it (and have port 6667 firewalled off for good measure), and use ssh port forwarding to connect from your laptop/desktop.

This will hopefully be more streamlined in the future; one possibility is to make the websocket solution used by the sandstorm version available for the non-sandstorm version as well.

License

Copyright (C) 2016  Ian Denhardt <[email protected]>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

(See COPYING for a copy of the license).

irc-idler's People

Contributors

zenhack avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

irc-idler's Issues

Fail more gracefully when multiple clients are "fighting" over login

I just had the following experience: I started up pidgin on my laptop, forgetting that I was signed in on my desktop. irc-idler then booted my desktop, because that's what it does when it gets a new connection. Then, my desktop tried to reconnect, which booted my laptop. rinse and repeat.

At some point, before I figured out what was happening, I rebooted the irc-idler, thinking it was hitting one of its more usual failure modes. This meant it had to reconnect to the server, and was no longer done with the handshake. Then, I started getting errors about excess floods, and the logs indicate that it was repeatedly reconnecting to the server as well.

This could happen if the new client connects before the server-side handhsake is finished; irc-idler will just drop everything and start over. So we repeatedly try to connect to the serer, and eventually it tells us to buzz off.

We should handle this more gracefully. Perhaps delay connecting to the server until we have the full user/nick/pass combo ready?

Ping-ponging the clients is something I'm willing to punt on, though eventually it might be nice to detect and handle this. But, we shouldn't cascade that to the server.

Persist logs to disk

I'm getting tired of losing the existing backlog whenever the program exits; this needs fixing. Now that the SQL storage backend is working we can start moving on this.

Be stricter about the role of session.Session

Conceptually this should just track the percieved state of the session by the client/server as appropriate, but there are some hacks in there (e.g. not updating the users in a channel until replay). This is conceptually weird and makes things harder to reason about. Proposal: we have two methods on Session, and the other state tracking types in that package: UpdateFromServer and UpdateFromClient, which get called whenever the client or server (as appropriate) sees a message. We can centralize these calls fairly easily, putting them in sendClient or such.

This will require coming up with a better way to track users in a channel and the way that interacts with the log, but... that's pretty broken as is.

Goroutine leak in websocket handler

See:

// XXX There's a bug in my websession pacakge that causes the
// connection to be dropped if this function returns. We're
// leaking goroutines on every connection now, but this at
// least "works." Fixing the bug and getting rid of this
// resource leak is high on my list of priorities.

This is a bug in the package "zenhack.net/go/sandstorm/websession", but since this repo is driving that one's development for now, and I want this on a specific milestone, I'm putting the issue here.

Sometimes users appear present on reconnect when they aren't

...and pidgin sometimes even displays multiple copies of the same user.

Part of this is that we're getting duplicate JOIN messages for the same user, without an intervining PART. This is unsurprising to me; the code that manages keeping track of this channel state is sloppy and broken in at least a couple ways that I'm aware of.

Weird hiccoughs when reconnecting.

Sometimes when I reconnect, the IRC Idler will drop the server connection and try to reconnect. This should happen if and only if the server-side of the session was in the middle of a handshake, which should only be the case if another client is connected, which should not be the case. Furthermore, the attempt to reconnect to the server hangs. If at some point another client tries to connect, this also deadlocks the http interface, as it will hang trying to pass the connection to the backend. See also zenhack/go.sandstorm#1

When this happens, I have to restart the grain to get it to start behaving again. The symptoms above are probably not all the same bug. I suspect that the hanging reconnect is related to #8.

Here is the bit of the grain console during this process:

time="2016-10-23T23:09:50Z" level=debug msg="serve(): Top of loop" 
** SANDSTORM SUPERVISOR: Grain has been backgrounded; staying up for now.
time="2016-10-23T23:10:20Z" level=debug msg="serve(): Top of loop" 
time="2016-10-23T23:10:50Z" level=debug msg="serve(): Top of loop" 
time="2016-10-23T23:11:20Z" level=debug msg="serve(): Top of loop" 
** SANDSTORM SUPERVISOR: Grain has been backgrounded; staying up for now.
time="2016-10-23T23:11:50Z" level=debug msg="serve(): Top of loop" 
time="2016-10-23T23:12:20Z" level=debug msg="serve(): Top of loop" 
sandstorm/supervisor.c++:438: error: exception = (remote):0: failed: remote exception: This vat does not expose any public/bootstrap interfaces.
stack: 0x437640 0x5ecec0 0x5ed930 0x444c90 0x459100 0x5ed930 0x5c73c0 0x5c7a20 0x5c7953 0x4a59a2
time="2016-10-23T23:12:34Z" level=debug msg="Sending client connection to daemon." 
time="2016-10-23T23:12:34Z" level=debug msg="serve(): Got client connection" 
time="2016-10-23T23:12:34Z" level=debug msg="dropClient(): dropping client connection." 
time="2016-10-23T23:12:34Z" level=debug msg="dropClient(): handshake incomplete; dropping server connection." 
time="2016-10-23T23:12:34Z" level=debug msg="Connecting to server..." 
time="2016-10-23T23:12:41Z" level=debug msg="Sending client connection to daemon." 
** SANDSTORM SUPERVISOR: Grain still in use; staying up for now.
** SANDSTORM SUPERVISOR: Grain has been backgrounded; staying up for now.
** SANDSTORM SUPERVISOR: Grain has been backgrounded; staying up for now.
** SANDSTORM SUPERVISOR: Grain has been backgrounded; staying up for now.

Codebase could use some reorganization

The overall directory structure is kindof haphazard; should step back and maybe think about the layout. it's not horrible, but could use some attention.

Don't block everything else when replaying messages.

Right now when a client reconnects and rejoins a channel, we replay all of the messages at once, and don't handle any more messages from either the client or the server until we're finished. This has a number of problems that crop up if we have a large number of messages to replay. Examples:

  1. We might not respond to server pings in a timely manner.
  2. We don't process other client messages, so if the user is trying to converse in another channel, nothing they send will get through until we're done replaying.

I'm sure there are more cases.

We ought to do this in a way that doesn't block other processing.

Duplicate MOTD responses on first connect

I'm pretty sure I know what's going on here, but I just got:

NICK isd
USER isd 0 * :Ian
:irc.example.net 001 isd :Welcome to the Internet Relay Network [email protected]
:irc.example.net 002 isd :Your host is irc.example.net, running version ngircd-23 (x86_64/unknown/linux-gnu)
:irc.example.net 003 isd :This server has been started Fri Sep 09 2016 at 17:39:09 (EDT)
:irc.example.net 004 isd irc.example.net ngircd-23 abBcCFiIoqrRswx abehiIklmMnoOPqQrRstvVz
:irc.example.net 005 isd RFC2812 IRCD=ngIRCd CHARSET=UTF-8 CASEMAPPING=ascii PREFIX=(qaohv)~&@%+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPQRstVz CHANLIMIT=#&+:10 :are supported on this server
:irc.example.net 005 isd CHANNELLEN=50 NICKLEN=9 TOPICLEN=490 AWAYLEN=127 KICKLEN=400 MODES=5 MAXLIST=beI:50 EXCEPTS=e INVEX=I PENALTY :are supported on this server
:irc.example.net 251 isd :There are 3 users and 0 services on 1 servers
:irc.example.net 254 isd 2 :channels formed
:irc.example.net 255 isd :I have 3 users, 0 services and 0 servers
:irc.example.net 265 isd 3 3 :Current local users: 3, Max: 3
:irc.example.net 266 isd 3 3 :Current global users: 3, Max: 3
:irc.example.net 250 isd :Highest connection count: 3 (5 connections received)
:irc.example.net 375 isd :- irc.example.net message of the day
:irc.example.net 372 isd :- "Hello world!"
:irc.example.net 376 isd :End of MOTD command
:irc.example.net 375 isd :- irc.example.net message of the day
:irc.example.net 372 isd :- "Hello world!"
:irc.example.net 376 isd :End of MOTD command

On reconnects, we send a MOTD command to the server to provoke the response; probably we're erroneously doing this on initial connect as well, causing a duplicate response.

Unable to store ipNetwork cap.

I'm not 100% sure this is even supposed to be persistent, but there's some disabled code that tries to save the cap to disk and then later restore it. The api.Save() appears to work, as does the restore, but actually using the cap doesn't. not sure what's up.

Test failures for the sql storage backend

...Which is currently still disabled, because of these.

I've temporarily disabled the tests so we still hear about other failures; this isn't top priority for me. But I want it recored on the issue tracker.

Send NICK errors to clients during the handshake.

Right now, like most things, we don't deliver these if the client isn't done with the handshake. However, this means that e.g. if the nick in question is taken, the client never hears about it. In the case of pidgin, this causes the handshake to never complete.

Set AWAY on disconnect

Might be nice to automatically set an away message when the client disconnects (and clear it on reconnect).

Add TLS option for Sandstorm

We currently don't expose the ability to connect to a server over TLS in the sandstorm version. This should change.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.