ndejong / pfsense_fauxapi

REST based API interface for pfSense 2.3.x and 2.4.x to facilitate devops
Apache License 2.0
354 stars 61 forks source link

How to apply when I config_set() the new configuration file #14

Closed GregoryZeng closed 6 years ago

GregoryZeng commented 6 years ago

I am currently writing a client for managing the "Host Overrides" table in "Services/DNS Forwarder" page and I succeed in posting a new JSON format configuration file via the config_set() API, which is proven by the instant change of table revealed in the web page (after my client emit that config_set() API).

However, it seems that though the shown table in the web page changes, the actual DNS behavior does not change as expected. Therefore, I am wondering if there is some mechanism I had ignored, like pressing the "apply" button when I manually change the table in the web page.

Another question: I still do not understand the difference between config_set() and config_reload(). The docs say that the former will call the latter when the code is "written and tested". What does it mean?

Thanks

ndejong commented 6 years ago

Based on your description where you say "Services DNS Forwarder" it seems you are therefore using dnsmasq under the covers because the "DNS Resolver" service is the Unbound service.

Digging through the pfSense code in services_dnsmasq_domainoverride_edit.php there is a last-moment call to services_dnsmasq_configure() before the call to write_config() and if we go and check that function it looks like pfSense causes dnsmasq to be restarted which pfsense_fauseapi does not handle, it would seem this is where you are running into issues.

The easiest way to resolve this might be to issue a send_event through pfsense_fauxapi with the payload service restart all taking this approach seems dirty and unnecessary, ideally you should be able to issue the payload service reload dnsmasq or service restart dnsmasq - I'm not able to test any of this from where I am at the moment but it seems fairly straight-forward to me.

WRT your question on the difference between config_set() and config_reload() - when you perform a config_set() call in pfsense_fauxapi you are in essence writing the config.xml file to pfSense, the function behind this does a number of sanity checks to make sure the config you have passed is structurally valid - it does this by converting the supplied config to XML, then reconverts this XML back into an array and then compares this with the supplied call input, if the two match then it is considered structurally valid - the config_reload() simply reloads the current pfSense configuration - by default a call to config_set() will automatically to a reload for you.

Please do report back on how you go

GregoryZeng commented 6 years ago

Thank you for your response!

As you'd advised, I tried send_event('service reload dnsmasq') but it does not work. Here is the response (I've masked the apikey field):

{'action': 'send_event',
 'callid': '59ffc29b1633d',
 'logs': [{'DATA': {'callid': '59ffc29b1633d',
    'client_ip': '10.130.18.78',
    'user_action': 'send_event'},
   'INFO': '20171105Z180203 :: fauxapi\\v1\\fauxApi::__call'},
  {'DEBUG': '20171105Z180203 :: fauxapi\\v1\\fauxApi::__check_user_action_call'},
  {'DEBUG': '20171105Z180203 :: fauxapi\\v1\\fauxApiAuth::is_authenticated'},
  {'DEBUG': '20171105Z180203 :: fauxapi\\v1\\fauxApiAuth::load_credentials'},
  {'DATA': {'apikey': xxx,
    'callid': '59ffc29b1633d',
    'client_ip': '10.130.18.78'},
   'INFO': '20171105Z180203 :: valid auth for call'},
  {'DEBUG': '20171105Z180203 :: fauxapi\\v1\\fauxApiAuth::is_authorized'},
  {'DATA': {'action': 'send_event',
    'permit': 'send_*',
    'permits': ['alias_*',
     'config_*',
     'gateway_*',
     'rule_*',
     'send_*',
     'system_*',
     'function_*']},
   'DEBUG': '20171105Z180203 :: permit allows action'},
  {'DEBUG': '20171105Z180203 :: fauxapi\\v1\\fauxApi::__check_user_action_call() checks all passed'},
  {'DEBUG': '20171105Z180203 :: fauxapi\\v1\\fauxApiActions::send_event'},
  {'DATA': 'service reload dnsmasq',
   'DEBUG': '20171105Z180203 :: fauxapi\\v1\\fauxApiPfsenseInterface::send_event'}],
 'message': 'ok'}

Likewise for the send_event('service restart dnsmasq') which does not work either. Here is the response:

{'action': 'send_event',
 'callid': '59ffc79860662',
 'logs': [{'DATA': {'callid': '59ffc79860662',
    'client_ip': '10.130.18.78',
    'user_action': 'send_event'},
   'INFO': '20171105Z182320 :: fauxapi\\v1\\fauxApi::__call'},
  {'DEBUG': '20171105Z182320 :: fauxapi\\v1\\fauxApi::__check_user_action_call'},
  {'DEBUG': '20171105Z182320 :: fauxapi\\v1\\fauxApiAuth::is_authenticated'},
  {'DEBUG': '20171105Z182320 :: fauxapi\\v1\\fauxApiAuth::load_credentials'},
  {'DATA': {'apikey': xxx,
    'callid': '59ffc79860662',
    'client_ip': '10.130.18.78'},
   'INFO': '20171105Z182320 :: valid auth for call'},
  {'DEBUG': '20171105Z182320 :: fauxapi\\v1\\fauxApiAuth::is_authorized'},
  {'DATA': {'action': 'send_event',
    'permit': 'send_*',
    'permits': ['alias_*',
     'config_*',
     'gateway_*',
     'rule_*',
     'send_*',
     'system_*',
     'function_*']},
   'DEBUG': '20171105Z182320 :: permit allows action'},
  {'DEBUG': '20171105Z182320 :: fauxapi\\v1\\fauxApi::__check_user_action_call() checks all passed'},
  {'DEBUG': '20171105Z182320 :: fauxapi\\v1\\fauxApiActions::send_event'},
  {'DATA': 'service restart dnsmasq',
   'DEBUG': '20171105Z182320 :: fauxapi\\v1\\fauxApiPfsenseInterface::send_event'}],
 'message': 'ok'}

Seems like the debug info from the response is not quite helpful? Since I know little about the implementation of pfsense and even PHP, I am wondering what shall I do next. What should I do to acquire more debug info?

I would greatly appreciate it with your help!

Thank you

GregoryZeng commented 6 years ago

Well, I got a bit confused about the services_dnsmasq_domainoverride_edit.php you've mentioned. Since I was to change the "Host Overrides" table rather than the "Domain Overrides" table in the "Services/DNS Forwarder" page, I am not sure if this file should be tracked.

GregoryZeng commented 6 years ago

I was just scanning through the services_dnsmasq.php and I saw these few lines of code:

if ($_POST['apply']) {
    $retval = 0;
    $retval |= services_dnsmasq_configure();
    // Reload filter (we might need to sync to CARP hosts)
    filter_configure();
    /* Update resolv.conf in case the interface bindings exclude localhost. */
    system_resolvconf_generate();
    /* Start or restart dhcpleases when it's necessary */
    system_dhcpleases_configure();
    if ($retval == 0) {
        clear_subsystem_dirty('hosts');
    }
}

I am wondering if it might help to call services_dnsmasq_configure(), filter_configure(), system_resolconf_generate() and system_dhcpleases_configure() in order via the funtion_call() API after I post a new conf file with new "Host Overrides" table.

Thank you

ndejong commented 6 years ago

The pfsense code behind this does not make it easy to provide any super useful debug return data here so it's a bit tough - also, the pfsense code that restarts dnsmasq handles the whole thing by killing the process which seems unusual.

There will be a way to handle all of this in a sane way and i like your use case, i have some time at the end of the week so i'll recreate your scenario myself and provide a sensible solution

You could try the following approaches in the mean time:-

On 6 Nov 2017, at 13:16, gregzeng notifications@github.com wrote:

Well, I got a bit confused about the services_dnsmasq_domainoverride_edit.php you've mentioned. Since I was to change the "Host Overrides" table rather than the "Domain Overrides" table in the "Services/DNS Forwarder" page, I am not sure if this file should be tracked.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ndejong/pfsense_fauxapi/issues/14#issuecomment-342036111, or mute the thread https://github.com/notifications/unsubscribe-auth/AAM2KlugajFg1CrJF_yah1A3ikOsEC_7ks5sznoRgaJpZM4QQzMH .

GregoryZeng commented 6 years ago

I tried calling services_dnsmasq_configure via the function_call API and it looks like that pfsense does "apply the changes" successfully. Also, I investigated this function in the pfsense/src/etc/inc/services.inc and it seems like this function kills the dnsmasq, performs some workarounds (which I don't fully grasp) and reruns the dnsmasq.

Anyway, I still look forward to your possible solution and your project is really awesome and very useful to me.

P.S. I found the path to the file of permitted function calls documented in your README.md seems inaccurate. At least in my case, it should be /etc/fauxapi/pfsense_function_calls.txt.

Thank you

GregoryZeng commented 6 years ago

Hi, I got a question on the "blockness" of the function_call API. Concretely, will the return of a client-side function_call indicate the return (end) of the pfSense-side function call? If not, how does the pfSense-side handles consecutive function_calls (or more generally, concurrent calls)?

Best Regards

ndejong commented 6 years ago

Hi Gregory - I missed your new-question about "blockness" on the back of this thread - the answer is that it is entirely up to pfSense itself - have a read of the Approach section of the documentation

ndejong commented 6 years ago

Closing this out - had kept open to resolve the documentation issue with /etc/fauxapi/pfsense_function_calls.txt - has been fixed in v1.3 due for a release shortly