Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please make bind address and port user configurable #3

Closed
kseistrup opened this issue Aug 11, 2023 · 5 comments
Closed

Please make bind address and port user configurable #3

kseistrup opened this issue Aug 11, 2023 · 5 comments
Assignees
Labels
enhancement New feature or request

Comments

@kseistrup
Copy link

Currently (v1.0.10 @ commit 8b70c23) remindme is listening on port 15555. As mentioned in #1, this port may already be in use on the local machine, in which case remindme will be unable to run.

Therefore it will make sense to make the listening port configurable.

In spite of what has been written about safe IP addresses in #1, it may also be useful to make the listening address configurable.

E.g., you could have more than once instance of remindme running locally by using 127.0.0.1, 127.0.0.2, …, or you could choose to let it bind to an address on a VPN so that several machines can share a single instance of remindme, or you could use it to overrride the default socket path (once that has been implemented).

The bind address and port could be specified via options for the remindme start command, or simply by using environment variables, e.g.:

  • $REMINDME_BIND_ADDR
  • $REMINDME_BIND_PORT

(_BIND can be omitted)

Ideally, $REMINDME_BIND_ADDR should default to a socket or to localhost, and $REMINDME_BIND_PORT could very well default to 15555 if the bind address is an IP address.

As also mentioned in #1, a safe choice for the socket name is $XDG_RUNTIME_DIR/remindme-$UID.socket, but the user may have a different opinion and specify the absolute path to the desired socket, in which case the $REMINDME_BIND_ADDR starts with a / (at least on linux/unix).

A configuration file can also be used, of course.


Redundant information: XDG Base Directory Specification:

@n0rdy
Copy link
Owner

n0rdy commented Aug 11, 2023

Hello there @kseistrup !

Thanks again for the detailed review and explanation.

Let me try to elaborate on some of these:

remindme is listening on port 15555. As mentioned in #1, this port may already be in use on the local machine, in which case remindme will be unable to run.
Therefore it will make sense to make the listening port configurable.

I do agree with this and I have this item in my TODO list. I haven't implemented this yet, as I haven't come up with the ideal way to do it (yet). While it is pretty easy to implement it for the HTTP server part of the app by using either:

  • environment vars (like you suggested)
  • a new flag for the start command (something like remindme start --port 14242)
  • config file
    it's a bit different for the client part of the app, because each command there runs the client app -> executes its logic (usually by making a call to the HTTP server) -> stops the client app -> return terminal input to the user.
    If the custom port is used, the client app needs to resolve it on (almost) each command and check the following places:
  • env var
  • config file
  • some other place if the remindme start --port 14242 approach is used (either some dedicated file within the file system, or a dedicated SQLite table for the metadata)
    What I'm trying to say is that running such simple commands like remindme list will potentially require some IO-calls to find the HTTP server port number (if env var approach is not used), which might be reduce the performance.
    However, since now there are 2 people (me included) who sees this as a beneficial feature to have, I will definitely try to implement it asap (either this weekend or next week, since the weather is nice again here =) )

In spite of what has been written about safe IP addresses in #1, it may also be useful to make the listening address configurable.
E.g., you could have more than once instance of remindme running locally by using 127.0.0.1, 127.0.0.2, …, or you could choose to let it bind to an address on a VPN so that several machines can share a single instance of remindme, or you could use it to overrride the default socket path (once that has been implemented).

That's an interesting suggestion, I haven't thought of this at all, tbh. I'll need to give it a thought and do some reading on the topic (as I don't have much experience in low-level network programming with Go). The initial idea was to make this tool as simple (for the end user) as possible, so, for example, the setup with sharing the instance among the machines might be too advanced tool-spirit-wise. Also, I'd like to double-check how portable this approach is for non-Linux OS (MacOS and Windows to be more specific), as those platforms are supported by the tool as well: as an option, I might need to implement a different approach for different OS:

  • Linux - socket approach (if permissions are in place)
  • otherwise - existing HTTP-server approach
    But I'll need to analyze it properly.
    Another thing to make sure for me is whether the underlined cross-OS notification library supports those usecases.

Anyway, I'll look into that, as this sounds like a fun and (potentially) useful thing to implement.

I wonder though whether the configurable address approach ($REMINDME_BIND_ADDR) might not open an attacking opportunity: if the bad actor manages to set this env var / config property to, for example, the public IP address of the machine, then the attack scenario from the #1 could become applicable here as well - I need to give this a thought.

But thanks again for the feedback and the cool ideas, I'll play with the things discussed above.

@n0rdy n0rdy self-assigned this Aug 11, 2023
@n0rdy n0rdy added the enhancement New feature or request label Aug 11, 2023
@kseistrup
Copy link
Author

[$REMINDME_BIND_ADDR] … if the bad actor manages to set this env var / config property to, for example, the public IP address of the machine …

The environment variables are all held in private memory. Nobody except the user themself can see or set the user's environment variables. If an adversary is able to set your environment variables, then you're already fscked.

running such simple commands … will potentially require some IO-calls to find the HTTP server port number …, which might be reduce the performance.

I don't think you need to worry about that. Countless programs are reading their configuration files or environment variables on each invocation, and we have never noticed.

I would suggest the following priority, and shortcut it on first match:

  1. Assume address and port both have their default values: localhost:15555. Proceed to the next step.
  2. Has the user provided a bind address or a port with a commandline option (e.g. --addr or --port)? If so, use these values and skip the next steps.
  3. Has the user set any known environment variables? If so, use these values and skip the next steps.
  4. Do we have a configuration file? Parse it, use the values, and skip the next step.
  5. Run with the default values.

For all it's worth, it's just three tiny tests.

@n0rdy
Copy link
Owner

n0rdy commented Aug 13, 2023

Thanks for the comment.

The environment variables are all held in private memory. Nobody except the user themself can see or set the user's environment variables. If an adversary is able to set your environment variables, then you're already fscked.

Agree. I mentioned this within the context of one of your previouss comments stating that

if somebody ssh's into a multiuser machine they will be able to add/edit/delete reminders that “belong” to the person who started remindme.

meaning that we are taking into account this very case.

For all it's worth, it's just three tiny tests.

The mentioned complexity comes not for the start command but rather for other commands (like list, in, etc.) that need to figure out the port the server is running on, as the app, from now on, needs to persists that port somewhere.

Anyway, I have already implemented the port changing feature. The app accepts the port number either via a new --port/-p flag for the start command like this:

remindme start --port 14242

or via the REMINDME_SERVER_PORT env var.

The port resolution order is the following:

  • --port/-p flag
  • env var
  • default value (15555)

As for the socket and address binding, I'm still considering whether this is something worth implementing for this simple app. I'll keep you posted.

@kseistrup
Copy link
Author

If an adversary is able to set your environment variables, then you're already fscked.

Agree. I mentioned this within the context of one of your previouss comments stating that

if somebody ssh's into a multiuser machine they will be able to add/edit/delete reminders that “belong” to the person who started remindme.

meaning that we are taking into account this very case.

I'm unsure if we are speaking about the same thing.

If user A logs into their account and launches a remindme server, they are the “owner” of said instance.
If we further assume that user A's account hasn't been compromised, then:
If users B‥Z logs into the same machine — be it as whitehats or blackhats — then they will not be able to read or write user A's environment variables, so they won't be able to access user A's remindme instance that way.
They will, however, be able to add, edit or delete any number of reminders by accessing user A's remindme instance via localhost because any port on localhost can be accessed by any logged in user.

It is for this reason that a socket (or similar) is not only nice-to-have on a multiuser machine, but need-to-have. If not, remindme can only be run safely on a strict single-user machine.

(I apologize in advance if I have misunderstood your messsages.)

@n0rdy
Copy link
Owner

n0rdy commented Jan 13, 2024

If an adversary is able to set your environment variables, then you're already fscked.

Agree. I mentioned this within the context of one of your previouss comments stating that

if somebody ssh's into a multiuser machine they will be able to add/edit/delete reminders that “belong” to the person who started remindme.

meaning that we are taking into account this very case.

I'm unsure if we are speaking about the same thing.

If user A logs into their account and launches a remindme server, they are the “owner” of said instance. If we further assume that user A's account hasn't been compromised, then: If users B‥Z logs into the same machine — be it as whitehats or blackhats — then they will not be able to read or write user A's environment variables, so they won't be able to access user A's remindme instance that way. They will, however, be able to add, edit or delete any number of reminders by accessing user A's remindme instance via localhost because any port on localhost can be accessed by any logged in user.

It is for this reason that a socket (or similar) is not only nice-to-have on a multiuser machine, but need-to-have. If not, remindme can only be run safely on a strict single-user machine.

(I apologize in advance if I have misunderstood your messsages.)

Hey, sorry, I missed your reply.

I reread your message and, yeah, you are absolutely right, it's important to have it on the multiuser machine.
However, this is far beyond the scope of this tool (for now?) - I moved to a maintenance mode due to other priorities at this moment.

But I greatly appreciate your input, and once I have more free time again, I'll consider implementing the socket version, as it sounds like both a useful and fun thing to do - that's why we code, isn't it? =)

@n0rdy n0rdy closed this as completed Jan 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants