As mentioned in #znc-dev, I'm currently working on a replacement for the identfile module that does not prevent concurrent connection attempts.
The current identfile module locks the ident file and blocks concurrent connection attempts, then directs the identd to reply with the connecting user's configured ident for all of ZNC's outgoing connections, and releases the lock when the connection is established (or the connection attempt fails).
My proposed alternative would require using oidentd, and take advantage of its ability to specify which connection a rule should apply to. For each outgoing connection, it would write a block like the following to the ident file:
to 1.2.3.4 fport 6667 from 5.6.7.8 lport 37470 {
reply "foo"
}
This requires us to know both the local IP address and the local port. In a comment to issue #460, it was mentioned that there would be a race condition if the ident file is written after connect() is called. This problem can be avoided by always explicitly calling bind() on the socket. The port to bind to would be specified as 0 to let the OS choose a suitable port. A call to getsockname() will then tell us which port was chosen.
This works well if a bind host is configured, in which case we know all the information needed to completely specify the connection in the ident file.
Problems arise if no bind host is configured:
We need to explicitly bind() the socket to get the local port before calling connect(). However, if no bind host is configured, we need to choose a local address to bind to. This address depends on the remote host: when connecting to an IPv4 host, we would bind to 0.0.0.0, and for an IPv6 host, we would bind to ::.
When using ZNC's threaded resolver, this is not a problem. The resolver will decide which remote IP address to connect to, and we can simply choose the matching IP to bind to before calling TSocketManager::Connect().
When not using ZNC's resolver, however, DNS is handled by Csocket, which would need to be modified for this approach to work.
Csocket resolves the bind host and binds to it before resolving the remote host. This means that we would need to decide on the bind address before we even know whether we are connecting to an IPv4 or IPv6 host. The "obvious" approach would be to swap the CST_DESTDNS and CST_BINDVHOST steps in Csocket, but:
If a remote host has both an IPv4 and an IPv6 address, we would need to bind() multiple times to different addresses, essentially combining CST_BINDVHOST and CST_DESTDNS/CST_CONNECT. I'm not comfortable fiddling with Csocket internals like this myself, especially since this might break other projects using Csocket.
If we bind() to 0.0.0.0 or ::, we don't know which local IP address was chosen until after the connect() call. This means that we must omit the from 5.6.7.8 part in the ident file, which could theoretically apply the ident to an unrelated connection in a very specific case if there is another outgoing connection from the same user that ZNC is running as. However, I believe this is not an issue (i.e. it cannot happen) if ZNC is run as a dedicated user.
Since I'd like to see this get merged, I wanted to ask for some feedback regarding these two points before spending too much more time on this.
Would it be acceptable to say that the new identfile module can only guarantee race-free operation when using ZNC's threaded resolver, or should I try to find a way to make it work with Csocket's resolver?
Can we simply "ignore" the second issue and tell people not to run other programs under the same user as ZNC? (Even if they disregard this, I believe the probability of this actually causing problems is exceedingly low.)
As mentioned in #znc-dev, I'm currently working on a replacement for the identfile module that does not prevent concurrent connection attempts.
The current identfile module locks the ident file and blocks concurrent connection attempts, then directs the identd to reply with the connecting user's configured ident for all of ZNC's outgoing connections, and releases the lock when the connection is established (or the connection attempt fails).
My proposed alternative would require using oidentd, and take advantage of its ability to specify which connection a rule should apply to. For each outgoing connection, it would write a block like the following to the ident file:
```
to 1.2.3.4 fport 6667 from 5.6.7.8 lport 37470 {
reply "foo"
}
```
This requires us to know both the local IP address and the local port. In [a comment to issue #460](https://github.com/znc/znc/issues/460#issuecomment-33033458), it was mentioned that there would be a race condition if the ident file is written after `connect()` is called. This problem can be avoided by always explicitly calling `bind()` on the socket. The port to bind to would be specified as `0` to let the OS choose a suitable port. A call to `getsockname()` will then tell us which port was chosen.
This works well if a bind host is configured, in which case we know all the information needed to completely specify the connection in the ident file.
Problems arise if no bind host is configured:
1. We need to explicitly `bind()` the socket to get the local port before calling `connect()`. However, if no bind host is configured, we need to choose a local address to bind to. This address depends on the remote host: when connecting to an IPv4 host, we would bind to `0.0.0.0`, and for an IPv6 host, we would bind to `::`.
When using ZNC's threaded resolver, this is not a problem. The resolver will decide which remote IP address to connect to, and we can simply choose the matching IP to bind to before calling `TSocketManager::Connect()`.
When *not* using ZNC's resolver, however, DNS is handled by Csocket, which would need to be modified for this approach to work.
1. Csocket resolves the bind host and binds to it before resolving the remote host. This means that we would need to decide on the bind address before we even know whether we are connecting to an IPv4 or IPv6 host. The "obvious" approach would be to swap the `CST_DESTDNS` and `CST_BINDVHOST` steps in Csocket, but:
2. If a remote host has both an IPv4 and an IPv6 address, we would need to `bind()` multiple times to different addresses, essentially combining `CST_BINDVHOST` and `CST_DESTDNS`/`CST_CONNECT`. I'm not comfortable fiddling with Csocket internals like this myself, especially since this might break other projects using Csocket.
2. If we `bind()` to `0.0.0.0` or `::`, we don't know which local IP address was chosen until after the `connect()` call. This means that we must omit the `from 5.6.7.8` part in the ident file, which could *theoretically* apply the ident to an unrelated connection in a very specific case if there is another outgoing connection from the same user that ZNC is running as. However, I believe this is not an issue (i.e. it cannot happen) if ZNC is run as a dedicated user.
Since I'd like to see this get merged, I wanted to ask for some feedback regarding these two points before spending too much more time on this.
Would it be acceptable to say that the new identfile module can only guarantee race-free operation when using ZNC's threaded resolver, or should I try to find a way to make it work with Csocket's resolver?
Can we simply "ignore" the second issue and tell people not to run other programs under the same user as ZNC? (Even if they disregard this, I believe the probability of this actually causing problems is exceedingly low.)
<!-- github-sync-id:642765773 -->
I'm currently working on a replacement for the identfile module that does not prevent concurrent connection attempts.
Hi, was there any progress?
Would it be acceptable to say that the new identfile module can only guarantee race-free operation when using ZNC's threaded resolver
Looks fine. I still hope to rewrite socket layer though.
Can we simply "ignore" the second issue and tell people not to run other programs under the same user as ZNC?
This can happen already with the current identfile module
> I'm currently working on a replacement for the identfile module that does not prevent concurrent connection attempts.
Hi, was there any progress?
> Would it be acceptable to say that the new identfile module can only guarantee race-free operation when using ZNC's threaded resolver
Looks fine. I still hope to rewrite socket layer though.
> Can we simply "ignore" the second issue and tell people not to run other programs under the same user as ZNC?
This can happen already with the current identfile module
<!-- github-comment-id:873698158 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
As mentioned in #znc-dev, I'm currently working on a replacement for the identfile module that does not prevent concurrent connection attempts.
The current identfile module locks the ident file and blocks concurrent connection attempts, then directs the identd to reply with the connecting user's configured ident for all of ZNC's outgoing connections, and releases the lock when the connection is established (or the connection attempt fails).
My proposed alternative would require using oidentd, and take advantage of its ability to specify which connection a rule should apply to. For each outgoing connection, it would write a block like the following to the ident file:
This requires us to know both the local IP address and the local port. In a comment to issue #460, it was mentioned that there would be a race condition if the ident file is written after
connect()is called. This problem can be avoided by always explicitly callingbind()on the socket. The port to bind to would be specified as0to let the OS choose a suitable port. A call togetsockname()will then tell us which port was chosen.This works well if a bind host is configured, in which case we know all the information needed to completely specify the connection in the ident file.
Problems arise if no bind host is configured:
We need to explicitly
bind()the socket to get the local port before callingconnect(). However, if no bind host is configured, we need to choose a local address to bind to. This address depends on the remote host: when connecting to an IPv4 host, we would bind to0.0.0.0, and for an IPv6 host, we would bind to::.When using ZNC's threaded resolver, this is not a problem. The resolver will decide which remote IP address to connect to, and we can simply choose the matching IP to bind to before calling
TSocketManager::Connect().When not using ZNC's resolver, however, DNS is handled by Csocket, which would need to be modified for this approach to work.
CST_DESTDNSandCST_BINDVHOSTsteps in Csocket, but:bind()multiple times to different addresses, essentially combiningCST_BINDVHOSTandCST_DESTDNS/CST_CONNECT. I'm not comfortable fiddling with Csocket internals like this myself, especially since this might break other projects using Csocket.If we
bind()to0.0.0.0or::, we don't know which local IP address was chosen until after theconnect()call. This means that we must omit thefrom 5.6.7.8part in the ident file, which could theoretically apply the ident to an unrelated connection in a very specific case if there is another outgoing connection from the same user that ZNC is running as. However, I believe this is not an issue (i.e. it cannot happen) if ZNC is run as a dedicated user.Since I'd like to see this get merged, I wanted to ask for some feedback regarding these two points before spending too much more time on this.
Would it be acceptable to say that the new identfile module can only guarantee race-free operation when using ZNC's threaded resolver, or should I try to find a way to make it work with Csocket's resolver?
Can we simply "ignore" the second issue and tell people not to run other programs under the same user as ZNC? (Even if they disregard this, I believe the probability of this actually causing problems is exceedingly low.)
Hi, was there any progress?
Looks fine. I still hope to rewrite socket layer though.
This can happen already with the current identfile module