Very Secure

The Story Told to Alcinoüs - the Cyclops

February 6th, 2020

In Book IX of The Odyssey, Odysseus recounts the part of his journey where his arrogance gets his entire crew killed. Odysseus doesn't see it that way and certainly doesn't make a point to acknowledge his culpability to his audience in Alcinoüs's hall. But unfortunately for Odysseus, I have the luxury of being able to reread and re-frame his tale.

Before getting some of his crew killed and the rest doomed to be killed later, Odysseus docks his fleet at an island abundant with food. Odysseus describes how fertile the land was, how the island had a stream of fresh water, how it had a bay safe for ships... Yet despite having found a goddamn oasis after toiling away at sea, Odysseus decides to leave for a nearby island. And once there, he thinks it smart to walk into a cave covered in massive piles of shit.1 Somehow the smell doesn't phase Odysseus and his men as they help themselves to some cheese.

The cyclops appears and isn't happy to find a bunch of men making themselves at home in his kitchen. He reclaims his food by eating the men who ate it. Odysseus and company can't escape because the cyclops moved a large boulder to block the door of the cave.2 So Odysseus comes up with a plan to get the cyclops drunk and stab him in the eye.

After Odysseus offers the cyclops wine, the cyclops becomes grateful and asks for his name. Wiley Odysseus tells the Cyclops that his name is "Noman." Odysseus pats himself on the back for this clever lie because later when the cyclops screams for help shouting, "I'm being attacked by Noman!" his other monster friends respond, "oh well if you're being attacked by 'no man' then I guess no one is attacking you hur der."

Odysseus and what remains of his crew manage to escape the cave, but Odysseus is not done being stupid. As he's sailing away he starts taunting the cyclops. The cyclops rips off part of a mountain and throws it at Odysseus's ship, missing by a hair. Having barely survived, Odysseus begins to taunt the cyclops again while his remaining crew is begging him to please stfu.

Unfortunately for the crew Odysseus does not listen and undoes his earlier act of cleverness by revealing his name. The cyclops then prays to his dad Poseidon to "please kill Odysseus, but if you can't do that then at least make his life hard and kill all his friends." The later part of the prayer comes true.

Odysseus's tale of being an idiot is well received in the hall of Alcinoüs. Stupidity mixed with "bravery" makes for fun stories.

  1. Odysseus doesn't mention the shit at first. He describes the pile of dung only later when he tells how he employed it as a hiding spot for the spear he used to blind the cyclops. []
  2. Odysseus conveniently doesn't mention the massive boulder until after it locked them inside the cave. But this boulder must have been rolled to the side of the entrance when they entered, right? Odysseus does say that when entering the cave in his "stout heart" he "suspected" he would meet a powerful savage. A real Sherlock Holmes, this Odysseus. []

The Right Kind of Positivity

February 4th, 2020

Jfw's refreshing and amusing "From the forum log" series includes a summary of a recent monologue from mp. The summary caught my attention and I daresay I have something to add to it after reading an article on human behavior linked in a comment mp left here.

First, the summary:

Trinque not having replied yet, MP expanded his own point on the suppression machine: going through life, one is constantly uncovering new personal deficiencies. Each time, one faces a difficult choice: to face and overcome it, painful because it requires killing a part of one's youth; to accept insufficiency; or to pretend it doesn't exist or doesn't matter and eventually end up an overgrown teenage loser (possibly hanging out in #asciilifeform to commiserate). He went on to note that the existence of evil(i) is essential for life to be interesting, but that this doesn't make it any less evil.

i. Or problems1

And the original:

mircea_popescu: every time you discover something, you get the same exact choice, again and again each time. you get the same choice that also happens to be the ~only~ meaningful choice you ever get, or ever could possibly get : are you going to fix it ?
mircea_popescu: there's strictly two possible answers you can ever produce, and they're yes or no. yes sucks because, well... it is suicide. [http://ossasepia.com/2019/10/31/working-with-ideals-and-perfections/#comment-6848][]quite literally], the little girl gotta die.
mircea_popescu: no sucks because... it really doesn't. once you decide you actually "like" your dysfunction, or in any case you're not equal to its remedial, you're stuck hanging out in #asciilifeform with all the other cripples.
mircea_popescu: your life becomes a carousel of a) identifying partitions upon the world that'll neatly divide it across the line of "this part exposes my dysfunction" / "this part doesn't expose my dysfunction" (definitionally an impossible task) and b) making up stories about how it all works out, or will, or whatever.
mircea_popescu: in the end, what you do is hang out with the other cripples. that's it, the loser table at the highschool cafeteria, where you tell each other stories of "how you aren't really geeks", and how one day you'll get the cheerleader, the usual fare. making pacts about losing your virginity by end of school...
mircea_popescu: it's not exactly novel, but on the contrary well documented to date. lotta cripples have lived since the practical implementation of rochester's all men be cowards if they durst.
mircea_popescu: it gets you stuck saying patently dumb shit like "alliance of the smart against the stupid" when what you quite transparently ~really~ mean is very much "i thought this guy was gonna vouch for my imaginary partitions of a) above!" ;
mircea_popescu: and everyone else is stuck somehow reconciling your supposed "great technical acumen" with your apparent incapacity to intellectually function enough to match a age-adequately developed nine year old slut -- which is incidentally how the elaborate narrative of the naysayers even evoloved over time : the others dealing with the anal child is how anal childhood even gets implanted in heads in the first place.
mircea_popescu: from whence it can further spread -- much like camels who never saw other camels spit don't know how to spit nor ever spit, while camels who did see other camels spit do know how and actually do it, just so people don't come up with evil naturally, they just replicate it from having seen it before.
mircea_popescu: this isn't a complaint -- i don't personally mind evil exists, nor do i believe it shouldn't exist or that its absence would signal any kind of improvement. without evil the world's boring as fuck, which is why idiots asking dumb questions like "how come an infinitely good god has small children raped to death" are fucking stupid. evil is a better addition to the world than fucking cinema, it'd be way too borning to try
mircea_popescu: and live without.
mircea_popescu: nevertheless -- this introduces no relativism. the ethical choice stays the ethical choice, and the moral state remains the moral state. yes or no, the perpetual question, and well... https://www.youtube.com/watch?v=3CTZty62iqo

The perpetual struggle to make the right decision at every juncture is made extra difficult by the brain's tendency to turn to fatlogic. It's not enough to make one tough choice to fix a deficiency. To mature one has to repeatedly go against their conditioning while fighting against extinction bursts.

This requires forming the habit of running towards the scary. And in order to build a habit of running towards the scary, one needs a positive outlook. This positive outlook is not the rhasta "don't worry, be happy" mentality, but instead a healthy focus on positive experience that lets one bear the cost required to improve.2

The rhasta mentality is one I have lived with for oh too long. Dealing with issues via imagination doesn't work; even with heroin you can't fully escape reality. I like my cheery disposition, but I need to ensure that my happiness is grounded in reality. Growing up I saw my father3, the live warning, reach the point where he was unemployed, playing solitaire all day, and taking molly-lite.4

It is difficult to be positive while experiencing the pain from exposing flaws for dissection. Temporarily suffering to improve in the long term is required. But being alive means *always* moving in the direction of improvement, never planning to stop at some higher comfort level. So one needs to learn to bear the pain and focus on enjoying the reality that manifests from making tough choices.

  1. Is this how one quotes a footnote - by manually writing it in the bottom of the blockquote? []
  2. As Naggum explains while discussing depression:

    depression is all about focusing on the negative things you observe, about expanding the impression of being "unlucky" to some kind of cosmic condition and from then on doing the opposite of what normal people do, which is to ignore the negative and the hardships because they _expect_ every ounce of positive experience to have a pound of cost, and they _know_ that errare humanum est, and that errors have costs, too. on top of this, the depressed tend not even to _see_ anything positive.

    []

  3. Who always appeared to be happy []
  4. Some antidepressant. I believe it was one of the popular SSRIs (Selective Serotonin Reuptake Inhibitors) []

ircbot no suicide on reconnect

February 2nd, 2020

ircbot-no-suicide-on-reconnect.vpatch
ircbot-no-suicide-on-reconnect.vpatch.whaack.sig

While writing fleetbot, whose functionality requires maintaining a whole lot of connections, I ran into a bug with ircbot's reconnection logic. The bug likely has stayed hidden because it manifests only when a specific thread calls ircbot-reconnect.1

The explanation of the bug is as follows:

Ircbot uses two threads. One thread is the run-thread that reads messages from the irc network and dispatches them to functions. The other thread, the ping-thread, sends a ping to the server every *ping-freq* seconds. The ping-thread also calls ircbot-reconnect if ircbot has not received a pong in *max-lag* seconds. ircbot-reconnect first calls ircbot-disconnect, which closes the connection and terminates the ping-thread. But since the active thread is the ping-thread when ircbot-disconnect is called, the ping-thread terminates itself. Thus the call to ircbot-reconnect never reaches the "connect" step of reconnection.

This vpatch changes ircbot so that ircbot-disconnect does not terminate the ping-thread if the ping-thread is nil or the active thread is the ping-thread. So now when the ping-thread successfully reconnects, it becomes the run-thread and spawns a new ping-thread to do its old job.2

In this patch I included two other changes:

1. I removed channel reconnection on kick. It's not explicitly stated in the #trilema bot spec, but I get the impression that bots are to do as told. If someone with the authority to do so kicks a bot, the bot should not fight back.

2. I fixed a misnamed parameter in make-ircbot.

1 diff -uNr a/botworks/ircbot/ircbot.lisp b/botworks/ircbot/ircbot.lisp
2 --- a/botworks/ircbot/ircbot.lisp c74e827a6c6c5cc4baf2bb72564e02a10057fd608cb1b11e504f81730ac30e2692bf54f5735faa6e4bd69be9f1ec9837cf12608551c0936653cf2880a54e2a6a
3 +++ b/botworks/ircbot/ircbot.lisp 9741409ae7fa93d709c729335c5396899d1b8f8f376d8fdd5284d9f1ddd073d1db49419fa859efe6b540c979990f16070137e849ee11e1ff57405ecdbc48a6cd
4 @@ -40,11 +40,6 @@
5 (add-hook conn 'irc-err_nicknameinuse-message (lambda (message)
6 (declare (ignore message))
7 (ircbot-randomize-nick bot)))
8 - (add-hook conn 'irc-kick-message (lambda (message)
9 - (declare (ignore message))
10 - (map nil
11 - (lambda (c) (join (ircbot-connection bot) c))
12 - (ircbot-channels bot))))
13 (add-hook conn 'irc-notice-message (lambda (message)
14 (ircbot-handle-nickserv bot message)))
15 (add-hook conn 'irc-pong-message (lambda (message)
16 @@ -65,7 +60,8 @@
17 (setf (ircbot-connection bot) nil)
18 (if (not (null (ircbot-run-thread bot)))
19 (sb-thread:terminate-thread (ircbot-run-thread bot)))
20 - (sb-thread:terminate-thread (ircbot-ping-thread bot))))
21 + (if (not (or (null (ircbot-ping-thread bot)) (equal sb-thread:*current-thread* (ircbot-ping-thread bot))))
22 + (sb-thread:terminate-thread (ircbot-ping-thread bot)))))
23
24 (defmethod ircbot-reconnect3
25 (let4)))
26 @@ -133,10 +129,10 @@
27 do (return t)))
28
29
30 -(defun make-ircbot (server port nick password channel)
31 +(defun make-ircbot (server port nick password channels)
32 (make-instance 'ircbot
33 :server server
34 :port port
35 :nick nick
36 :password password
37 - :channel channel))
38 + :channels channels))
39 diff -uNr a/botworks/manifest b/botworks/manifest
40 --- a/botworks/manifest b4d189ecf4e93ea7539d9512dc7554c44ca759712e0b035f04a850f508c84a244dae778387edd6e6a463204d35bf3ed8246ded018581cd4b8347189948cef643
41 +++ b/botworks/manifest 22d9a0246e251298ccfa31918fc9193b306aa202bf103ac2ad92b9920c40eb5cca7b10fa4e400e92b2b39a8a2483fe7d2a0295add1ce548d66b9373c12fa4928
42 @@ -1,2 +1,3 @@
43 424545 ircbot-genesis trinque ircbot genesis, http://trinque.org/2016/08/10/ircbot-genesis/
44 447104 ircbot-multiple-channels-corrected ben_bulpes multiple channel support for ircbot, http://cascadianhacker.com/correction-multiple-channel-patches-for-irclogbot
45 +615488 ircbot-no-suicide-on-reconnect whaack fixes reconnect bug + removes rejoin on chan kick, http://ztkfg.com/2020/02/ircbot-no-suicide-on-reconnect/
46

Although not included in this vpatch, ircbot would benefit from a better reconnection strategy. Currently it attempts to reconnect only once. And since the bot detected lag prior to the moment it attempts to reconnect, it is likely that that the one reconnect attempt will not succeed. So although this vpatch fixes a logical error, I am doubtful that it will increase ircbot's uptime by much. I will submit another vpatch with a more aggressive reconnection strategy once I have fleshed out all the details for its use case with fleetbot.

  1. This bug will be invisible to someone calling ircbot-reconnect in the repl. []
  2. This is not the case if one started ircbot by running ircbot-connect-thread. In that situation, the ping-thread calls ircbot-connect-thread and terminates. ircbot-connect-thread creates a new run-thread as well as a new ping-thread. []
  3. bot ircbot) &optional (quit-msg "..." []
  4. threaded-p (not (null (ircbot-run-thread bot []

Network Socket Notes

January 31st, 2020

While working on TheFleet I came across questions difficult to answer with my minimal understanding of the system level functions used to send messages over a network. So I read a guide on the subject1 and took notes. The aim of this article is to present those notes in a manner that gives clarity to how certain c functions allow one to communicate over a network via the abstraction of writing to and reading from a unix file.

File descriptors

Each unix process has its own file descriptor table.2 Each row in that table contains the memory address of a file. When a process calls a system level function that interacts with a file, the process must pass the file's file descriptor3 as a parameter to the function.

Sockets

int socket(int domain, int type, int protocol);4

A socket is a special type of unix file used for either local inter process communication or communication over a network. The function socket creates a socket and returns its socket descriptor.5

Making a socket available to the world

int bind(int sockfd, struct sockaddr *my_addr, int addrlen);6

Calling bind tells the kernel to tie a socket to an (ip address, port) pair.7 The pair serves as the address of the socket on the internet.

Establishing connections

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);8

connect establishes a connection to a remote socket. Just like bind, connect tells the kernel to tie the given socket to an (ip address, port) pair. This pair is used as the return address for messages sent to the remote socket. The kernel picks a random available port for this purpose. Thus when a process sends a packet over the internet, it almost always uses a port number different than the one used in the foreign address.9

A process can implement typical server behavior by passing a socket descriptor to the functions bind, listen, and accept in order to establish many connections on the same local port.

int listen(int sockfd, int backlog);10

listen tells the kernel to create a limited size queue for incoming connections. Connection attempts are rejected whenever the queue is full.

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept pops connections off of the listen queue. It returns a new socket descriptor to be used for the connection.

Established connections are uniquely determined by (source ip, source port, foreign ip, foreign port) tuples. So a machine with one ip address has a theoretical limit of 65536 * 65536 established connections per foreign ip address. Resource limitations make the maximum number of possible connections much smaller in practice.

One can see established connections with the command:

netstat -natu | grep 'ESTABLISHED'

Sending and receiving messages

Once a socket has an established connection, the functions send and recv are used to write and read from the socket.

int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, int flags);

send and recv do not guarantee to write or read all len bytes.

send returns the number of bytes actually sent or -1 on error.

recv returns the number of bytes actually read, 0 if the remote side closed the connection, or -1 on error.

Closing connections

int close(int sockfd);

close, the function used for closing files in general, is used to close a connection.

  1. Perhaps I should have spent more time looking for a better source of information. The author of this guide one seems to have some right ideas and occasionally is funny,

    They say absence makes the heart grow fonder, and in this case, I believe it to be true. (Or maybe it’s age.) But what I can say is that after a decade-plus of not using Microsoft OSes for my personal work, I’m much happier! As such, I can sit back and safely say, “Sure, feel free to use Windows!” …Ok yes, it does make me grit my teeth to say that.

    but despite knowing better he bows to the crowd

    At this point in the guide, historically, I’ve done a bit of bagging on Windows, simply due to the fact that I don’t like it very much. But I should really be fair and tell you that Windows has a huge install base and is obviously a perfectly fine operating system.

    The guide also includes sections on writing IPV6 compatible code. I skimmed over them. IPV6 is the network equivilant of Gavin monster blocks. []

  2. If a process forks the child process is given a copy of the parent process's table. Changes in the two tables are not shared between the child and the parent. If both parent and child try to read from the same file, the one that calls read first gets the data. []
  3. i.e. the index of the file in the process's file descriptor table []
  4. The parameters given to socket determine whether the socket will use the tcp or udp as well as whether it will be used for network or local communication. []
  5. A socket descriptor is a file descriptor that refers to a socket. Socket descriptors and file descriptors share the same table. []
  6. sockaddr is a struct of address information that includes the (ip address, port) pair. []
  7. The ip address can be a loopback address such as 127.0.0.1 if the socket is being used for local communication. []
  8. for connect, sockaddr refers to the remote address. []
  9. Previously, I had the misconception that the same port was used for each side of the client and server pair. []
  10. The parameter backlog determines the length of the queue of incoming connections. It should be <= to the system limit, which is usually around 20 []

A confession of how I waste time 2

January 29th, 2020

A confession of how I waste time 1

Last week my productivity slacked. I constantly paused work to do mindless activities. Lack of focus is an ongoing problem,1 but this past week my symptoms were more severe than usual. I figure one way to address the issue is to write an article revealing some of the embarrassing ways I waste my time.

The first is I listen to music during work and in between tasks. Before I do the dishes or some mundane chore, I put on a song. This makes all the small jobs I need to do around the house take longer. I recently knocked over a pot of hot coffee while changing a song, splattering shattered glass and liquid all over my kitchen.

I've mentioned this problem before. What I didn't mention was the exact "music" I listen to. I always put on something by Russ, a rapper who raps about being hard working and self made. So yeah, just about everyday for months I've been being lazy and listening to the same chord progressions accompanied with lyrics about how someone else's hard work led them to success.

The lyrics of Russ's song, Me You, are ohso fitting. Russ raps about the difference in work ethic between him and the listener.

...
Yeah, mm yeah, there's a difference
Oh yeah, there's a difference
Oh, yeah, there's a difference
There's a difference, yeah
Yeah, yeah, yeah

Me, got it out the mud, they respect that
Me, always spread the love when I get back
You, got your hand out, that's a bitch move
You, always complaining like a bitch do
Me, still right here with who I came with
Me, self-made, my circles on the same shit
You, got a different crew every weekend
You, don't want it that bad, keep sleeping
Yeah, you wished for it, me, I worked for it
...

2

Another way I burn the precious minutes of life is by watching surf videos on youtube.3 I've tried to prevent myself from doing this by null routing www.youtube.com by inserting "0.0.0.0 www.youtube.com" into my hosts file. But the fake resistance doesn't help, I always find some justification for commenting out the line.

These two specific avoidance behaviors are likely symptoms and not the source of my problem. But maybe analyzing the symptoms can help discover the root. The connection I see between the two aforementioned activities are they are low effort ways I use to hallucinate success. While listening to Russ, I am imagining myself as having already reached success through hard work. While watching the surf videos, I am imagining myself on large perfect waves. I might as well spend the time watching videos on other sites. I'd be doing the same thing except I'd have something to show for it when I finish.

  1. As I'm sure it is in the lives of most. []
  2. Quite the poetry when you see the lyrics written out, yeah, yeah, yeah. []
  3. I also go out and surf, that is after all a major reason I live where I do now. But I've reduced the time spent surfing to a healthy 5-7 hours per week. It has been easy to not avoid work through surfing, because there has been very little swell the past few months. Am I going to be able to forgo getting in the water when I see glassy barrels out my window? []

Fleetbot Pseudocode, Bugs and Fixes, and the New Next Steps

January 26th, 2020

Below is an overview of how TheFleet works on a per network basis. The article also touches on a bug I found in cl-irc, enumerates the hurdles I have to overcome related to orchestrating the fleet of fleetbots, and lists my next steps forward.

Table of Contents:

I. Fleetbot class template
II. Connecting basics
III. How fleetbot handles various irc messages
IV. Reconnecting
V. Notes on logging
VI. A bug in cl-irc
VII. Problems with orchestration
VIII. Next steps

I. Fleetbot class template

Below is the fleetbot class template. Some of the fields are inherited from its superclass, ircbot.

Field Name Datatype Description
db list a list of four strings (db_name, db_user, db_user_password, db_ip_addr) used for connecting to the postgres db.
sunk-p boolean set to true if the bot has disconnected, false otherwise
resurface-attempts integer the number of consecutive failed attempts to connect to a network. gets reset to 0 upon a successful connection. a connection is deemed successful when we receive our join message from the server1 for any channel in our lists of channels.
connection cl-irc class an object representing the connection to the network. ~all cl-irc commands take this object as the first parameter.2
channels list a list of strings that are the names of channels the bot will attempt to connect to.
active-channels list a list of strings that are the names of channels we are currently connected to. upon being kicked from a channel, we remove the channel from active-channels. upon being disconnected, we remove all channels by setting active-channels to nil. we add the corresponding channel to active-channels when we receive back our join message from the network.
networkname string the name of the irc network the bot connects to
server string the hostname of the network
port int the port number of the network (usually 6667)
nick string the nick we use for the network
current-nick string the nick that we are using for our current connection. this is the same as nick, unless the server told us we could not use nick (most likely because nick is already being used.) in this case we append "-???" to nick where each ? is a random digit 0-9.
password string the password for the nick. since we do not use registered nicks for fleetbot, this field is always nil.
connection-security :ssl or :none the connection security for the network. currently we do not connect to networks via ssl, so this is always set to :none
run-thread sb-thread the thread that is used for communicating with the server
ping-thread sb-thread the thread that is used for sending pings to the server
lag int the difference between the last time we sent the server a ping and the time we received the server's corresponding pong.
lag-track list everytime we send the server a ping we store a reference to the ping in the lag-track. when we receive the corresponding pong from the server we delete the ping from the lag-track. if we have not received a pong in response to a ping for > *max-lag* (default = 60) seconds we determine we have disconnected, and the ping-thread will attempt to reconnect our bot to the network.

II. Connecting basics

The fleetbot constructor takes as parameters: the server information (networkname, server, and port), a nick, a list of channels, and the db used for logging.

We then connect fleetbot via the overwritten method ircbot-connect-thread. ircbot-connect-thread creates a new thread, assigns that thread to the bot's run-thread field, and within the new thread calls ircbot-connect.

ircbot-connect is surrounded in a handler-case.3

First, ircbot-connect calls cl-irc's function connect, which takes a nickname, server, port, and connection-security and returns a connection object. The connection object provides an interface to send and receive messages from the irc server via cl-irc's api. Next, we use cl-irc's api to add a list of hooks to the connection object. A hook is a mapping of an irc message type to a function. When we receive a message via the socket stored in the connection object, cl-irc searches for hooks that are assigned to the message's message type and calls the hook's function with the message passed as the sole parameter.

If at any point an error is thrown, then we mark the bot as "sunk" and attempt to reconnect the bot. If we cannot reconnect after +MAX-RESURFACE-ATTEMPTS+ (default = 5) attempts then we determine the bot has sunk for good and stop trying to reconnect.

III. How fleetbot handles various irc messages

We have the following hooks setup:

IRC Message Type Function Description
irc-err_nicknameinuse-message We change our nick by appending a random suffix. (i.e. jenny -> jenny-482)
irc-kick-message The intended behavior is to log that we are kicked and then remove the channel from our active-channels.

Currently upon being kicked from a channel, we have a bug where we immediately try to rejoin all channels in fleetbot's channels field.4

irc-notice-message A notice message is an arbitrary message from the server. Different networks send different notice messages. For our purposes, we parse the message to see if the server is telling us that the nickname we're trying to use is registered. If so, then we pick a new randomize nick, just like we do when we receive irc-err_nicknameinuse-message. Afaik this is only useful for freenode.
irc-pong-message When we receive a pong message we calculate our lag with the server and mark that the server has received our ping.
irc-rpl_welcome-message Upon receiving the welcome message from the server, we start the ping-thread and connect our bot to its channels via cl-irc's join method.
irc-privmsg-message A privmsg is any normal user message sent to a target.5 We log privmsg's to the irclog table in our postgres db.
irc-part-message A part message gets sent when a user leaves a channel. We log these to our irclog along with privmsg's.
irc-join-message A join message gets sent when a user joins a channel. We log joins to our irclog along with part and privmsg's. If the join message is saying that ~we~ joined the channel, then: we add the channel to our list of active channels, we log to fleetlog that we joined a channel, and we set our consecutive-resurface-attempts back to 0.

After we set all the above hooks, we enter an infinite loop reading messages from the server. If we have a hook for the message type of a message we received, we dispatch to the corresponding function. If we receive a message type that we don't have a hook for, the default-hook from cl-irc gets called, which usually just prints the message to STDOUT. If at anypoint during our infiniteloop the server sends us an EOF or we throw any error, we attempt to reconnect.

IV. Reconnecting

Reconnecting is a bit tricky because there are two different threads that can call reconnect: the bot's run-thread and the bot's ping-thread. The run-thread would be reconnecting because the run-thread received an EOF from the server or hit an error during its operation. The ping-thread would be reconnecting because it hasn't received a pong to one of our pings from the server in *max-lag* seconds.

The reconnect flow is as follows:

First, we call ircbot-disconnect. ircbot-disconnect sets sunk-p to true6 and then logs an internal DISCONNECTED message to fleetlog for all the active-channels the bot was connected to. Then we set active-channels to nil. If we have an active connection to the network, we close that connection. Then we set the ircbot's lag-track and ircbot-connection to nil. Then, if we are calling disconnect from the run-thread, we kill the ping-thread. If we are calling disconnect from the ping-thread, we kill the run-thread.7 We then set the ping-thread to nil.

Once we've disconnected cleanly, we attempt to connect. If we are the run-thread we call ircbot-connect. If we are the ping-thread, we make a new thread with ircbot-connect-thread, and then call sb-thread:abort-thread to end the current thread.8 Then we set sunk-p to false.

V. Notes on logging

Our schema has two tables - irclog and fleetlog. We insert into irclog the types of messages one would normally see in their irc client: privmsg, join, part, and kick messages. Fleetlog, on the other hand, keeps a record of our bot's events that we choose to store. For each event we log: a custom message describing the event, the channel (if applicable), the nick (if applicable), the networkname, and the time the event occurred. The custom messages currently logged are:

Message Description
JOINED logged for a channel+nick when we receive a join message from the server where we were the ones who joined
KICKED logged for a channel+nick when we get kicked from a channel
DISCONNECTED logged for every active-channel when we call ircbot-disconnect
COULD-NOT-RECONNECT logged for every channel we failed to connect to when we have failed a consecutive series of attempts to reconnect
ARMADA-ALL-DEAD logged for a network when all bots (within a process) connected to a network have crashed
PROCESS-TERMINATED logged for a network when we end the process running fleetbot (either because all ships have sunk or because the process received a kill signal)

The schema for the postgres db is pasted below. Noticably missing is the indexing for fleetlog.


set search_path = public;

create table irclog (
    id serial primary key,
    target text not null,
    message text not null,
    host text,
    source text not null,
    "user" text,
    networkname text not null,
    irc_message_type text not null,
    received_at timestamp without time zone not null default (now() at time zone 'utc')
);

create index irclog_received_at on irclog (received_at);
create index irclog_target on irclog (target);
create index irclog_source on irclog (source);
create index irclog_networkname on irclog (networkname);

create table fleetlog (
    id serial primary key,
    channel text,
    message text not null,
    nick text,
    networkname text not null,
    received_at timestamp without time zone not null default (now() at time zone 'utc')
);

Also, when I run fleetbot, I redirect standard out to a log file. The log file contains prints of unhandled irc messages and debugging print statements I put inside fleetbot.

VI. A bug in cl-irc

I gave the cl-irc source a pass and noticed a bug that affects fleetbot. cl-irc has a global variable *unknown-reply-hook* that can be assigned a function. That function is supposed to be called anytime an irc network sends a message of unknown type. However, the code that throws the no-such-reply error in cl-irc is malformatted.

This9

(error "Ignore unknown reply." 'no-such-reply :reply-number reply-number)

should be:

(error 'no-such-reply :reply-number reply-number)

The bug in cl-irc made the no-such-reply error bypass cl-irc's own handler-case10, throwing the error upstream to fleetbot. Fleetbot handles all errors by reconnecting. So upon receiving an unknown reply, fleetbot would reconnect and then usually receive the same unknown reply, causing fleetbot to reconnect again ad infinitum. I will patch cl-irc with the above fix and then set *unknown-reply-hook* to a function that logs unknown replies to fleetlog.

VII. Problems with orchestration

I need to rewrite how I orchestrate the fleet of fleetbots. Here are the constraints I am dealing with:

1. An irc network typically only allows 3 connections per IP.

2. A VM with 1GB of RAM costs me $5 / month.

3. A unix process running sbcl and asdf consumes 30MB of RAM at minimum. Currently a running fleetbot consumes closer to 100 MB.

4. A unix sbcl process has a maximum number of threads that it can have running concurrently.11

5. A unix sbcl process has a maximum number of sockets it can have open.

6. A unix process has a maximum number of filedescriptors it can use. (adjustable with ulimit)

VIII. Next steps12

1. Publish vpatch addressing ircbot's reconnect bug

2. Fix reconnect on kick bug

3. Increase delay before reconnecting to a network

4. Patch cl-irc + create way to distribute fix to VMs (after I patch I can no longer load cl-irc via quicklisp)

5. Set *unknown-reply-hook* to a function that logs unknown replies to fleetlog

6. Fix fleetbot's db schema

7. Write article planning how to address orchestration of bots

  1. To join a channel, we send the server a join message. If the join is successful, we receive the same join mesage we sent back from the server. []
  2. Under the hood, connection uses usocket:socket-connect to create a socket connected to the irc network. Then the socket is passed to usocket:socket-stream to get the network-stream. cl-irc creates an output-stream (used for sending messages to the network) by passing the network-stream to flexi-streams:make-flexi-stream. I haven't explored the usocket nor flexi-streams library at this time. []
  3. A handler-case is Common Lisp's version of a try/catch block. []
  4. I discovered this only now and it is the cause of problems I've run into.. The weird part of the bug is that we rejoin all channels when we are kicked from only one channel. This may explain why I saw "ERR_TOOMANYCHANNELS" messages despite limiting the length of channel-list to the max number of channels alllowed per nick on the network. []
  5. A target is either a nick or a channel. []
  6. I realized that ircbot-reconnect was setting sunk-p to false, ~before~ we call ircbot-disconnect. So all of our bots that reconnected once were being incorrectly marked as sunk. This has been fixed. []
  7. This is handled incorrectly in the current version of ircbot. In ircbot, the ping-thread kills the ping-thread (itself) when trying to reconnect, thus crashing the bot. Since there is a few pieces of republican infrastructure sitting ontop of ircbot, it is a top priority to create a vpatch that fixes this. []
  8. But I realize there is no reason for this "create new thread and then self destruct". At this point the ping-thread can stop doing its pinging job and just become the run thread. []
  9. I do not know why the author of cl-irc put the string "Ignore unknown reply." as the first parameter. The first parameter instead should be the condition type. []
  10. try/catch block []
  11. 2048 iirc. There is likely a way to increase this number. []
  12. Updated from my last plan []

Holy shit, lizard hitler's scheme to scare people away from non-https sites is working

January 24th, 2020

Do you remember when Googlag and other agents of the evil empire conspired to push everyone onto their https scam? A few years ago they updated their browsers to display a "not secure" warning when connected to a non-https compliant site. I had forgotten about this myself, until recently when I shared my blog with someone at a bar. He pulled up my site on his phone and immediately commented that it was not secure. Gasps and whispers could be heard from onlookers, insecure! wasn't whaack just talking about how he was interested in cryptography?

Naively, I responded by trying to explain why one should ignore the browser's warning. But countering ignorance with a wordy rational argument is pointless at best and autistic at worst. My explanation came off defensive. I should have thrown him something out of the blue.

I left the bar wondering: could Goolag & co's scheme be driving away a substantial amount of tmsr readership? On the bright side the https warning may serve as a helpful filter. If you fall for it, God help you. But perhaps there are some confused souls with potential being led astray. The pretense that Googlag gives for requiring https may be convincing to someone who has not yet "negrated" the certificate signing authorities. Think of the children!

Whether the "not secure" warning does more harm (by blocking potential noobs) than good (by filtering out the cluess) is unclear. The problem is that tmsr has no say in the matter. There's no way around this if it's a given that the enemy controls what is displayed on their cattle's screen.1 But so long as they don't modify my site itself, I can leave a little signal on the top left corner of my page.

  1. I'm sure they would prefer to ban all sites outside of NSABook/Instaspam/Goolag/etc. Apple's walled-garden app store is most of the way there. []

Installing Software on the New Machine

January 23rd, 2020

After various delays, I have finally put together a machine running CentOS-6.9-x86_64-minimal.iso. My next task is to install necessary software. First I must clarify what I want to do with the computer.

The reasons I built the computer are:

1. To have a machine I can trust1 that allows me to be maximally productive.

2. To gain a better understanding of the hardware and software I use.

3. To rid myself of my dependency on a company that treats its customers like cattle.

Keeping these reasons in mind, I need to go forward with the goal of installing software I've read and understood. Unfortunately, fully understanding each piece of code I use is an unrealistic ideal. Computing has perhaps left the world of math and entered the world of biology. The complexity is too great, so certain items will be installed on faith.

To give direction on what I need to install, I put together a list of what I would like to do with my machine.

1. Blog

2. Program

3. Communicate through IRC

4. Play Eulora

5. (Optional) Run a bitcoin node

In order to obtain what I need to do the above, I must setup software that helps me install other software. This begins by installing a V, or even better by writing my own V. Then I need to configure a network connection.

In order to blog I must install emacs, a graphics stack, and a web browser. I will install all three with yum. These pieces of software are examples of tools I depend on that I don't have time to fully read and understand. Also, by installing via yum, I am placing confidence in signatures from keys unknown to any of my trusted peers.

In order to write programs, I will need to setup my emacs environment. At a minimum I will need to make sure I have syntax highlighting. Some other features I find useful are jump-to-function-definition and auto-complete. However I am not so sure that these tools help me. Lastly, to continue my work on TheFleet, I will need to install sbcl, quicklisp, slime, and postgres.

For communicating through IRC, I will use V to press jfw's yrc client.

I noticed that there is no guide on Eulora's website for installing the game on CentOS. So I will try to compile the client from source and of course ask for help in #o or #e.

And lastly, for installing a bitcoin node I will use V to press trb.

There are other tasks I must do to setup my computer. For example, I need to setup an SSH key and add the public key to my VMs and blogs, etc. But the above list should keep me busy for now.

  1. to a certain degree []

Spanish Pop Study - An Attempted Translation of Dollar by Becky G and Myke Towers - Part 2

January 22nd, 2020

Continued from part 1

Yo sé que hay muchos en fila
Y que te cansaron las mentiras, deja que el destino decida
Tú estás por encima, siempre por mi mente desfilas
No hay otra parecida, que tú eres única
La foto viral a la que la haces pública
Vámonos de vacaciones pa' la República
Con una como tú uno lo que quiere es turistear,
Pero ella me tumba el plan
Myke Towers, baby

I know that there are many in line
And that they tire you with lies, let fate decide1
You are on top, you always run through my mind
There's no one similar, you are unique
The viral foto is that which you make public2
Let's go on vacation to the (Dominican) Republic
With someone like you the desire is to travel3
But she owns my plan
Myke Towers, baby

Hook x1

Becky G responds

No me pongas esa cara
Con esos ojitos no me vas a convencer
Sabes que mi amor es caro
Si lo quieres, tú tienes que trabajar por el (Por fa', eh)
Si te dijo que me bajes el cielo (Ey), me lo bajas entero (¡Wuh!)
Si te dijo que vengas, me traigas hasta el mar (Rrr), cruza los 7 mares (Ah ah)
Así es que se hacen las cosas con esta muchacha
Quiero más acción y menos blah-blah

Don't put on that face
With those little eyes you're not going to convince me.
You know my love is expensive.
If you want it, you have to work for it (Please, eh)
If I tell you to lower the sky, (ey) you lower it all the way (wuh)
If I tell you to come, you carry me to the sea, (Rrr) across the 7 seas (ah ah)
That's how things are done with this girl
I want more action and less blah-blah.

Hook x2

Luian (Yeah yeah yeah)
¡Mambo Kingz! (Jajaja)
Hydro
Jowny
Myke Towers, baby

Every Spanish pop song seems to end with some promotional shoutouts.

  1. Or literally, "let destiny decide" []
  2. Another translation says, "The viral photo you make public" . I am doubting both translations. I am unsure of what Myke Towers is trying to say here. []
  3. Another translation says, "with a girl like you, what you want is to be a tourist." From my first understanding, it is ambiguous whether the subject of querer (to want) is the third person or second person formal. However upon further examination I believe that its conjugation is meant to be in the second person formal. There is no context for a third person here. []

El Toro

January 22nd, 2020

The crowd splits; the beast charges in my direction. A paralysis seizes me. Just stay still, close your eyes, it'll be okay. Now I understand the headlight effect. But I am no deer. I scramble away, unsure where to face while running. Look forward, lose site of bull. Look back, collide or trip.

I head for the fence, the way out. There are other dangers. I dodge a man. I dodge a horse. Almost free. I slide under the fence. Should have climbed it. Legs have reached safety, head and torso have not. There are spectators blocking my exit. I kick the assholes until they move. Safe.

I go for a walk, dusting off my clothes. My camera is missing, but what does that matter?