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

Refactor getBestPublicIp for all valid ips #1132

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

sgourdas
Copy link
Collaborator

@sgourdas sgourdas commented Sep 12, 2024

This refactors getBestPublicIp(bool) to getBestPublicIps(IpMode) so it can correctly return all attached ips for both protocols ipv4 and ipv6.

Fixes kiwix/kiwix-tools#703
Fixes kiwix/kiwix-tools#709

Copy link

codecov bot commented Sep 12, 2024

Codecov Report

Attention: Patch coverage is 32.65306% with 33 lines in your changes missing coverage. Please review.

Project coverage is 41.38%. Comparing base (0b14fda) to head (c8a11be).

Files with missing lines Patch % Lines
src/tools/networkTools.cpp 42.85% 3 Missing and 13 partials ⚠️
src/server/internalServer.cpp 16.66% 7 Missing and 3 partials ⚠️
src/server.cpp 28.57% 3 Missing and 2 partials ⚠️
src/server/internalServer.h 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1132      +/-   ##
==========================================
- Coverage   41.43%   41.38%   -0.06%     
==========================================
  Files          59       59              
  Lines        4245     4265      +20     
  Branches     2323     2338      +15     
==========================================
+ Hits         1759     1765       +6     
- Misses        990      996       +6     
- Partials     1496     1504       +8     
Flag Coverage Δ
41.38% <32.65%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@kelson42
Copy link
Collaborator

@sgourdas thx for the PR but can you please fix the code so the CI can pass?

@sgourdas
Copy link
Collaborator Author

@kelson42 ready

Copy link
Collaborator

@kelson42 kelson42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost good, but

$ kiwix-serve --port=8080 -i 127.0.0.1 /home/kelson/Downloads/wikipedia_en_ray_charles_maxi_2023-12.zim 
The Kiwix server is running and can be accessed in the local network at: http://192.168.0.168:8080 and http://::1:808

Should return only http://127.0.0.1:8080 as kiwix-serve should only listen on this IP

include/server.h Outdated Show resolved Hide resolved
@kelson42
Copy link
Collaborator

Still not working fine:

$ kiwix-serve --port=8081 -i ipv4 /home/kelson/Downloads/wikipedia_fr_climate_change_maxi_2022-05.zim 
The Kiwix server is running and can be accessed in the local network at: http://:8081

@sgourdas Please test all of this completly.

@sgourdas
Copy link
Collaborator Author

Still not working fine:

$ kiwix-serve --port=8081 -i ipv4 /home/kelson/Downloads/wikipedia_fr_climate_change_maxi_2022-05.zim 
The Kiwix server is running and can be accessed in the local network at: http://:8081

@sgourdas Please test all of this completly.

@kelson42 I tested this and it was working fine for me. Tested again and I get:

kiwix-serve --port 8081 -l /home/ubunter/.local/share/kiwix-desktop/library.xml -i ipv4
Loading the library from the following files:
        /home/ubunter/.local/share/kiwix-desktop/library.xml
The library was successfully loaded.
The Kiwix server is running and can be accessed in the local network at: http://172.27.70.65:8081

@sgourdas
Copy link
Collaborator Author

Have you built both new kiwix tools and libkiwix versions?

If yes, can you provide more details like if despite the printed message the server is available in browser?

src/server/internalServer.cpp Outdated Show resolved Hide resolved
include/server.h Outdated Show resolved Hide resolved
include/tools.h Outdated Show resolved Hide resolved
src/server/internalServer.cpp Outdated Show resolved Hide resolved
src/server/internalServer.h Outdated Show resolved Hide resolved
test/server_testing_tools.h Outdated Show resolved Hide resolved
include/tools.h Outdated Show resolved Hide resolved
@kelson42
Copy link
Collaborator

@sgourdas This will wait tomorrow, I kind of suspect something wrong in my testing because of the renaming of the .pc file done earlier today and not fully rolled-out.

@kelson42
Copy link
Collaborator

@sgourdas Still wrong! You are "cheating" (taking for IPV4 the localhost instead of the public IP)!

$ kiwix-serve --port=8383 -i ipv4 /home/kelson/Downloads/wikipedia_fr_climate_change_maxi_2022-05.zim 
The Kiwix server is running and can be accessed in the local network at: http://127.0.0.1:8383

@sgourdas sgourdas removed the request for review from veloman-yunkan September 18, 2024 15:16
@sgourdas sgourdas marked this pull request as draft September 18, 2024 15:33
Copy link
Collaborator

@veloman-yunkan veloman-yunkan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I started reviewing while the PR was being updated. My feeling is that my feedback doesn't pave the path to this PR being merged on next iteration, it seems like we will have to make at least a couple more back-and-forths.

include/server.h Outdated Show resolved Hide resolved
src/server/internalServer.cpp Outdated Show resolved Hide resolved
src/tools/networkTools.cpp Outdated Show resolved Hide resolved
src/tools/networkTools.cpp Outdated Show resolved Hide resolved
src/tools/networkTools.cpp Outdated Show resolved Hide resolved
include/server.h Outdated Show resolved Hide resolved
@sgourdas
Copy link
Collaborator Author

I think I started reviewing while the PR was being updated. My feeling is that my feedback doesn't pave the path to this PR being merged on next iteration, it seems like we will have to make at least a couple more back-and-forths.

Sorry for this. This PR is not up to standard and I have to revise all the changes. When it started, I expected it to be more straight forward and it has become very unstructured.

Will try to get back ASAP.

@sgourdas sgourdas force-pushed the feature/best-public-ip branch 4 times, most recently from d87643d to 97ad823 Compare September 19, 2024 08:47
@sgourdas sgourdas marked this pull request as ready for review September 19, 2024 12:55
@kelson42
Copy link
Collaborator

Seems to work now! How do we secure that only valid IP are given/accepted for -i?

@sgourdas
Copy link
Collaborator Author

Seems to work now! How do we secure that only valid IP are given/accepted for -i?

Perfect. Currently, we are using inet_pton() accordingly for v4 or v6 addresses. If the conversion is successful we know that it is valid and of that type.

@kelson42
Copy link
Collaborator

@sgourdas This IP 192.168.0.0 is not available on my system, but I have no error telling me the IP is not valid.

kelson@camber:~/code/kiwix-tools$ kiwix-serve --port=8081 -i 192.168.0.0 /home/kelson/Downloads/wikipedia_en_ray_charles_maxi_2023-12.zim 
Unable to instantiate the HTTP daemon. The port 8081 is maybe already occupied or need more permissions to be open. Please try as root or with a port number higher or equal to 1024.

@sgourdas
Copy link
Collaborator Author

@sgourdas This IP 192.168.0.0 is not available on my system, but I have no error telling me the IP is not valid.


kelson@camber:~/code/kiwix-tools$ kiwix-serve --port=8081 -i 192.168.0.0 /home/kelson/Downloads/wikipedia_en_ray_charles_maxi_2023-12.zim 

Unable to instantiate the HTTP daemon. The port 8081 is maybe already occupied or need more permissions to be open. Please try as root or with a port number higher or equal to 1024.

What should be the proper behaviour for this case in your opinion? I think this should be a topic for another PR if it add features that were not present before.

@kelson42
Copy link
Collaborator

@sgourdas OK, I have open kiwix/kiwix-tools#709
@sgourdas @veloman-yunkan We should move aheqd with code review IMO now that it works from a user perspective.

Copy link
Collaborator

@kelson42 kelson42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from a user perspective

Copy link
Collaborator

@veloman-yunkan veloman-yunkan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we should close #1136 and bring its enhancement into this PR.

include/server.h Show resolved Hide resolved
include/tools.h Outdated Show resolved Hide resolved
src/server.cpp Outdated Show resolved Hide resolved
test/otherTools.cpp Outdated Show resolved Hide resolved
@@ -16,7 +16,7 @@

namespace kiwix {

enum class IpMode { ipv4, ipv6, all };
enum class IpMode { ipv4, ipv6, all, flex };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me flex is not an intuitive term for the intended mode of operation.

In the coding style that I got used to, enum members names must be in UPPERCASE. In this case that would have helped to avoid the problem with auto being a keyword in C++. Please rename existing members of IpMode in a separate commit, then add a new member IpMode::AUTO.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the feeling I have missed something... what is his "glex" option!? Where does it come from?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kelson42 It started from here

src/server.cpp Show resolved Hide resolved

if (!ipv4 && !ipv6) {
const std::string& addr = m_addr.addr.empty() ? m_addr.addr6 : m_addr.addr;
std::cerr << "IP address " << addr << " is not valid" << std::endl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore the previous text of the error message

src/tools/networkTools.cpp Show resolved Hide resolved
Comment on lines +217 to +218
bool validMode4 = (mode == IpMode::ipv4 || mode == IpMode::all); // Mode is valid to support ipv4
bool validMode6 = (mode == IpMode::ipv6 || mode == IpMode::all); // Mode is valid to support ipv6
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that these can be moved to the bottom of the function. The function will consist of two parts

  • select the best public IPv4 and IPv6 addresses regardless of the mode requested (the logic of this will be slightly simpler compared to the current code)
  • compose the result from those IPv4 and IPv6 addresses based on the requested mode

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am debating whether we should do a mode check inside this function at all. The name getBestPublicIps I think better suits a behavior where the whole IpAdress struct is filled. IMO mode checking should be moved outside this function.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. In fact, when writing my previous comment I considered proposing to package the first part (covered by the first bullet) into a separate function IpAddress getBestPublicIps(void). I even think that you proposed something like that earlier.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I even think that you proposed something like that earlier.

Indeed, you did.

for (const auto& [_, interfaceIps] : interfaces) {
if (!bestPublicIps.addr.empty() && validMode4 && !interfaceIps.addr.empty() && interfaceIps.addr.find(prefix) == 0)
bestPublicIps.addr = interfaceIps.addr;
if (!bestPublicIps.addr6.empty() && validMode6 && !interfaceIps.addr6.empty())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the interfaceIps.addr.find(prefix) == 0 check omitted intentionally?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the reason it is omitted is because we only provide v4 prefixes.

Copy link
Collaborator Author

@sgourdas sgourdas Sep 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be beneficial to provide some for v6?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the reason it is omitted is because we only provide v4 prefixes.

The purpose of this piece of code is to select an IP address from a local network, though I am not sure why the 169.254 prefix (see https://en.wikipedia.org/wiki/Link-local_address) has not been included. Your selection of an IPv6 address fails to meet that criteria. Why don't you filter based on the same IPv4 check (interfaceIps.addr.find(prefix) == 0) but use the IPv6 address (interfaceIps.addr6)?

Would it be beneficial to provide some for v6?

According to https://en.wikipedia.org/wiki/Link-local_address#IPv6

  • In IPv6, unicast link-local addresses are assigned from the block fe80::/10

however, unfortunately, it seems like fe80 cannot be used as a prefix because only its higher 10 bits matter. If we decide to support it a slightly more complex check will be required. But let's not go after it now.

test/otherTools.cpp Show resolved Hide resolved
* @param addr the IP address to check.
* @return true if the IP address is available on the system.
*/
bool ipAvailable(const IpAddress& addr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. This function need to be a part of the public API?
  2. IpAddress can be a pair of addresses (one IPv4 and the other IPv6). How is this function supposed to work if both components are non-empty?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function need to be a part of the public API?

I think it can be a useful function to have available

IpAddress can be a pair of addresses (one IPv4 and the other IPv6). How is this function supposed to work if both components are non-empty?

Current use case was to check only one ip (in the case of the user giving one). I will refactor it to take as a parameter the mode as well and check accordingly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function need to be a part of the public API?

I think it can be a useful function to have available

When dealing with public API that's not a good argument. Public API is a commitment. Exposing something just because it's useful may lead to unjustified maintenance overhead (like having to deal with backward compatibility issues). Let's not bloat our public API without necessity.

@sgourdas
Copy link
Collaborator Author

Sorry for the lack of feedback here. Getting back tomorrow morning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants