Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login

    How does it work in the Background?

    Captive Portal
    2
    11
    1.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • E
      eterelle
      last edited by

      Hello Everyone,

      i would like to better understand how the captive portal works in the background. From what i understood by looking at the code and trying a few things in the pfsense shell, it looks like it's creating ipfw rules for authorized clients matching their mac and ip address. All other requests seem to be forwarded to the local webserver at port 8002. What i don't understand is, that i thought pfsense uses pf as a firewall. It makes sense to use ipfw for the Captive Portal as it can allow / block packets based on the mac address(as far as i understood), but i don't quite understand the order in which packets are filtered. Does it first go through pf and then through ipfw, or vice versa? Or something completely different?

      I hope someone can point me in the right direction, as i didn't find any info online.

      F 1 Reply Last reply Reply Quote 0
      • F
        free4 Rebel Alliance @eterelle
        last edited by

        @eterelle said in How does it work in the Background?:

        Hello Everyone,

        i would like to better understand how the captive portal works in the background. From what i understood by looking at the code and trying a few things in the pfsense shell, it looks like it's creating ipfw rules for authorized clients matching their mac and ip address. All other requests seem to be forwarded to the local webserver at port 8002. What i don't understand is, that i thought pfsense uses pf as a firewall. It makes sense to use ipfw for the Captive Portal as it can allow / block packets based on the mac address(as far as i understood), but i don't quite understand the order in which packets are filtered. Does it first go through pf and then through ipfw, or vice versa? Or something completely different?

        I hope someone can point me in the right direction, as i didn't find any info online.

        Hi,
        That's correct, pfSense is using ipfw as backend for the captive portal

        And yes, pfsense is normally using pf for most of its functionalities (traffic shaper/ firewall/NAT, etc....) but it has been decided to use ipfw for this specific feature

        It may seems odd at first....but in fact it make some sense : it help to split the firewall and cp modules

        ipfw is triggered before pf (when a packet arrives, it goes first to ipfw if loaded...then to pf).

        Ipfw is not enabled by default on pfsense. The kernel module is loaded automatically when a captive portal is enabled

        Also, the PHP code is using specific functions to interact with ipfw, These functions are written in c (in pfSense.c, on the ports repository) and interact directly with the kernel, instead of using the ipfw command

        Also, two web servers (1 for http, another one for https if enabled) are set up per zone, starting from port 8002 and 8003 (if you create another zone, port 8004 and 8005 will be used, etc...)

        Users are identified based on their mac address+IP address couple (or based on their IP only if you disable MAC authentication)

        Does that answers most of your questions?

        E 1 Reply Last reply Reply Quote 0
        • E
          eterelle @free4
          last edited by

          @free4 Yes, that was really helpful, thanks! As a background info on why i want to know this, I am trying to make a pfsense package to control internet access of individual users using another custom software and i thought the captive portal would be a good example on how something like that could be implemented.
          Maybe you can also help me understand this ipfw rule:

          01000   19700    2547034 skipto tablearg ip from any to any via table(cp_ifaces)
          

          From what i understand, this skips to another rule if traffic enters via an interface enabled in the captive portal config. But where does it skip to(seems like it skips over the allow any rule)?

          Thank you for helping, that was already really useful for me!

          F 1 Reply Last reply Reply Quote 0
          • F
            free4 Rebel Alliance @eterelle
            last edited by free4

            @eterelle I am not 100% sure (I don't have a pfsense available for test right now) but if I recall correctly this rule redirects ("skip to") packets to the rules of the interface it is coming from

            The captive portal can be enabled on multiple interfaces (/multiple zones can be enabled).

            ipfw rules are structured this way:

            • first are the general rules (which 1000 skipto tablearg all from any to any via table(cp_ifaces) is part of)

            • then the rules relative to each interface (allow DHCP and DNS, forward HTTP to the web server, allow traffic which is part of table ${cpzone}_auth_up and ${cpzone}_auth_down etc)

            • then the "final" rules (allow all / block all. These rules are used because there is some "skipto" pointing to them)

            E 1 Reply Last reply Reply Quote 0
            • F
              free4 Rebel Alliance
              last edited by free4

              I also remember that this very specific line is the root cause of a bug

              https://redmine.pfsense.org/issues/7553

              The algorithm used internally by tablearg does not support having network cards which begin by the same name

              when you have em0 and em0.243 (because you created a vlan 243 on em0)...setting up a captive portal on em0 cause em0.243 to also be blocked.

              It's a freeBSD kernel bug at this point, not a pfsense one. But still "funny" to look at

              E 1 Reply Last reply Reply Quote 0
              • E
                eterelle @free4
                last edited by

                @free4 Here are all the rules:

                01000   19700    2547034 skipto tablearg ip from any to any via table(cp_ifaces)
                01100 1497103 1515944168 allow ip from any to any
                02100       0          0 pipe tablearg ip from any to any MAC table(test_pipe_mac)
                02101       0          0 allow pfsync from any to any
                02102       0          0 allow carp from any to any
                02103     855          0 allow ip from any to any layer2 mac-type 0x0806,0x8035
                02104       0          0 allow ip from any to any layer2 mac-type 0x888e,0x88c7
                02105       0          0 allow ip from any to any layer2 mac-type 0x8863,0x8864
                02106       6          0 deny ip from any to any layer2 not mac-type 0x0800,0x86dd
                02107    1123      85710 allow ip from any to table(test_host_ips) in
                02108    1097     320180 allow ip from table(test_host_ips) to any out
                02109       7       2370 allow ip from any to 255.255.255.255 in
                02110       0          0 allow ip from 255.255.255.255 to any out
                02111       0          0 pipe tablearg ip from table(test_allowed_up) to any in
                02112       0          0 pipe tablearg ip from any to table(test_allowed_down) in
                02113       0          0 pipe tablearg ip from table(test_allowed_up) to any out
                02114       0          0 pipe tablearg ip from any to table(test_allowed_down) out
                02115     918     193474 pipe tablearg ip from table(test_auth_up) to any layer2 in
                02116    1390     510141 pipe tablearg ip from any to table(test_auth_down) layer2 out
                02117    1293     108852 fwd 127.0.0.1,8002 tcp from any to any 80 in
                02118    1095     129016 allow tcp from any to any out
                02119   11916    1197291 skipto 65534 ip from any to any
                65534   11916    1197291 deny ip from any to any
                65535       4        186 allow ip from any to any
                

                Also, if i run ipfw table cp_ifaces list, it shows this:

                ipfw table cp_ifaces list
                --- table(cp_ifaces), set(0) ---
                re1.40 2100 273 21692 1599332255
                

                I didn't really find anything about what the second value means, but as there is a rule with the number 02100, i guess maybe it skips to there?
                That would be this rule:

                02100       0          0 pipe tablearg ip from any to any MAC table(test_pipe_mac)
                

                which seems to be for the traffic shaper / rate limiter, but the traffic is only piped into there if the mac is listed in test_pipe_mac, which seems to be a list of mac addresses allowed under the MACs Tab in the CP config, so this rule would not envoke normally.

                So i think for clients who are authenticated, the rules 2111 - 2116 would allow traffic, and for non authenticated users, all requests will be forwarded to 127.0.0.1:8002 by rule 2117.

                Does that look correct to you?

                F 1 Reply Last reply Reply Quote 0
                • E
                  eterelle @free4
                  last edited by

                  @free4 Yeay, that's a really unintuitive bug.. Thanks in advance for saving me from some possible problems there :)

                  1 Reply Last reply Reply Quote 0
                  • F
                    free4 Rebel Alliance @eterelle
                    last edited by free4

                    @eterelle the traffic shaper is using pf

                    The second rule you've shown correspond to the "Allowed MAC" feature... (the MAC tab)
                    You should have the same ipfw tables for "allowed IPs" of each zone

                    E 1 Reply Last reply Reply Quote 0
                    • E
                      eterelle @free4
                      last edited by

                      @free4 Yes, i didn't mean the Traffic Shaping feature of pfsense but the Traffic Shaper of ipfw(or at least the manpage of ipfw says that the pipe command is used for the traffic shaper, so i figured that it is used for the Bandwidth limit that can be set in the Allowed MACs config).

                      F 1 Reply Last reply Reply Quote 0
                      • F
                        free4 Rebel Alliance @eterelle
                        last edited by

                        @eterelle yup, I understand

                        Aside from this..your guesses are correct

                        Since you plan to create an external package, I advice you to have a look to the ACME module of pfsense (how it is structured, etc...)

                        ACME is a package that generates let's encrypt certificates. It is based on acme.sh

                        I do suggest you to have a look to this package because...it is up to date, using some advanced functionality of packages, and it is maintened/developed by the core pfsense team

                        Many modules (eg, freeRadius) are legacy/out of date and should not really be taken as reference...

                        E 1 Reply Last reply Reply Quote 0
                        • E
                          eterelle @free4
                          last edited by

                          @free4 I will definetely have a look at that. Thanks for all the help, i really appreciate it!

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post
                          Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.