Added send/recv CoA methods to the server.
authorAlan T. DeKok <aland@freeradius.org>
Tue, 19 May 2009 06:56:33 +0000 (08:56 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 19 May 2009 06:56:33 +0000 (08:56 +0200)
Many modules have been updated to be able to process CoA packets.
The server core has been updated to process CoA packets.  However,
it does not yet actually listen on a CoA port.

21 files changed:
raddb/experimental.conf
raddb/modules/perl
raddb/radiusd.conf.in
raddb/sites-available/originate-coa
share/dictionary.freeradius.internal
src/include/modules.h
src/include/radius.h
src/main/modcall.c
src/main/modules.c
src/main/radclient.c
src/main/util.c
src/modules/rlm_always/rlm_always.c
src/modules/rlm_detail/rlm_detail.c
src/modules/rlm_jradius/rlm_jradius.c
src/modules/rlm_linelog/rlm_linelog.c
src/modules/rlm_perl/rlm_perl.c
src/modules/rlm_policy/parse.c
src/modules/rlm_policy/rlm_policy.c
src/modules/rlm_python/radiusd_test.py
src/modules/rlm_python/rlm_python.c
src/modules/rlm_ruby/rlm_ruby.c

index efd715d..95c8c93 100644 (file)
                mod_accounting = radiusd_test
                func_accounting = accounting
 
-               mod_preproxy = radiusd_test
-               func_preproxy = preproxy
+               mod_pre_proxy = radiusd_test
+               func_pre_proxy = pre_proxy
 
-               mod_postproxy = radiusd_test
-               func_postproxy = postproxy
+               mod_post_proxy = radiusd_test
+               func_post_proxy = post_proxy
 
-               mod_postauth = radiusd_test
-               func_postauth = postauth
+               mod_post_auth = radiusd_test
+               func_post_auth = post_auth
+
+               mod_recv_coa = radiusd_test
+               func_recv_coa = recv_coa
+
+               mod_send_coa = radiusd_test
+               func_send_coa = send_coa
 
                mod_detach = radiusd_test
                func_detach = detach
index c16c42e..d961b11 100644 (file)
@@ -42,6 +42,8 @@ perl {
        #func_pre_proxy = pre_proxy
        #func_post_proxy = post_proxy
        #func_post_auth = post_auth
+       #func_recv_coa = recv_coa
+       #func_send_coa = send_coa
        #func_xlat = xlat
        #func_detach = detach
 
index e081861..0dd0eab 100644 (file)
@@ -247,6 +247,9 @@ listen {
        #               raddb/sites-available/copy-acct-to-home-server
        #       status  listen for Status-Server packets.  For examples,
        #               see raddb/sites-available/status
+       #       coa     listen for CoA-Request and Disconnect-Request
+       #               packets.  For examples, see the file
+       #               raddb/sites-available/coa-server
        #
        type = auth
 
index 0124117..9dc5844 100644 (file)
@@ -117,7 +117,7 @@ home_server localhost-coa {
 home_server_pool coa {
        type = fail-over
 
-       # Point to the CoA server aboce.
+       # Point to the CoA server above.
        home_server = localhost-coa
 
        #  CoA requests are run through the pre-proxy section.
index ec81886..83ee02e 100644 (file)
@@ -207,6 +207,12 @@ ATTRIBUTE  EAP-MSK                                 1129    octets
 ATTRIBUTE      EAP-EMSK                                1130    octets
 
 #
+#      For send/recv CoA packets (like Auth-Type, Acct-Type, etc.)
+#
+ATTRIBUTE      Recv-CoA-Type                           1131    integer
+ATTRIBUTE      Send-CoA-Type                           1132    integer
+
+#
 #      Range:  1200-1279
 #              EAP-SIM (and other EAP type) weirdness.
 #
index 6b8e211..c6eaf84 100644 (file)
@@ -24,7 +24,11 @@ enum {
   RLM_COMPONENT_PRE_PROXY,     /* 5 */
   RLM_COMPONENT_POST_PROXY,    /* 6 */
   RLM_COMPONENT_POST_AUTH,     /* 7 */
-  RLM_COMPONENT_COUNT          /* 8: How many components are there */
+#ifdef WITH_COA
+  RLM_COMPONENT_RECV_COA,      /* 8 */
+  RLM_COMPONENT_SEND_COA,      /* 9 */
+#endif
+  RLM_COMPONENT_COUNT          /* 8 / 10: How many components are there */
 };
 
 #define RLM_TYPE_THREAD_SAFE           (0 << 0)
@@ -68,6 +72,13 @@ int module_checksimul(int type, REQUEST *request, int maxsimul);
 int module_pre_proxy(int type, REQUEST *request);
 int module_post_proxy(int type, REQUEST *request);
 int module_post_auth(int type, REQUEST *request);
+#ifdef WITH_COA
+int module_recv_coa(int type, REQUEST *request);
+int module_send_coa(int type, REQUEST *request);
+#define MODULE_NULL_COA_FUNCS ,NULL,NULL
+#else
+#define MODULE_NULL_COA_FUNCS
+#endif
 int indexed_modcall(int comp, int idx, REQUEST *request);
 
 /*
index e671b13..c7946a9 100644 (file)
 #define PW_MODULE_RETURN_CODE          1108
 #define PW_PACKET_ORIGINAL_TIMESTAMP           1109
 #define PW_HOME_SERVER_POOL            1111
+#define PW_RECV_COA_TYPE               1131
+#define PW_SEND_COA_TYPE               1132
 
 /*
  *     Integer Translations
index 3954c73..6137e12 100644 (file)
@@ -304,7 +304,12 @@ static int default_component_results[RLM_COMPONENT_COUNT] = {
        RLM_MODULE_FAIL,        /* SESS */
        RLM_MODULE_NOOP,        /* PRE_PROXY */
        RLM_MODULE_NOOP,        /* POST_PROXY */
-       RLM_MODULE_NOOP         /* POST_AUTH */
+       RLM_MODULE_NOOP         /* POST_AUTH */
+#ifdef WITH_COA
+       ,
+       RLM_MODULE_NOOP,        /* RECV_COA_TYPE */
+       RLM_MODULE_NOOP         /* SEND_COA_TYPE */
+#endif
 };
 
 
@@ -1178,6 +1183,87 @@ defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
                        MOD_ACTION_RETURN       /* updated  */
                }
        }
+#ifdef WITH_COA
+       ,
+       /* recv-coa */
+       {
+               /* group */
+               {
+                       MOD_ACTION_RETURN,      /* reject   */
+                       MOD_ACTION_RETURN,      /* fail     */
+                       3,                      /* ok       */
+                       MOD_ACTION_RETURN,      /* handled  */
+                       MOD_ACTION_RETURN,      /* invalid  */
+                       MOD_ACTION_RETURN,      /* userlock */
+                       1,                      /* notfound */
+                       2,                      /* noop     */
+                       4                       /* updated  */
+               },
+               /* redundant */
+               {
+                       MOD_ACTION_RETURN,      /* reject   */
+                       1,                      /* fail     */
+                       MOD_ACTION_RETURN,      /* ok       */
+                       MOD_ACTION_RETURN,      /* handled  */
+                       MOD_ACTION_RETURN,      /* invalid  */
+                       MOD_ACTION_RETURN,      /* userlock */
+                       MOD_ACTION_RETURN,      /* notfound */
+                       MOD_ACTION_RETURN,      /* noop     */
+                       MOD_ACTION_RETURN       /* updated  */
+               },
+               /* append */
+               {
+                       MOD_ACTION_RETURN,      /* reject   */
+                       1,                      /* fail     */
+                       MOD_ACTION_RETURN,      /* ok       */
+                       MOD_ACTION_RETURN,      /* handled  */
+                       MOD_ACTION_RETURN,      /* invalid  */
+                       MOD_ACTION_RETURN,      /* userlock */
+                       2,                      /* notfound */
+                       MOD_ACTION_RETURN,      /* noop     */
+                       MOD_ACTION_RETURN       /* updated  */
+               }
+       },
+       /* send-coa */
+       {
+               /* group */
+               {
+                       MOD_ACTION_RETURN,      /* reject   */
+                       MOD_ACTION_RETURN,      /* fail     */
+                       3,                      /* ok       */
+                       MOD_ACTION_RETURN,      /* handled  */
+                       MOD_ACTION_RETURN,      /* invalid  */
+                       MOD_ACTION_RETURN,      /* userlock */
+                       1,                      /* notfound */
+                       2,                      /* noop     */
+                       4                       /* updated  */
+               },
+               /* redundant */
+               {
+                       MOD_ACTION_RETURN,      /* reject   */
+                       1,                      /* fail     */
+                       MOD_ACTION_RETURN,      /* ok       */
+                       MOD_ACTION_RETURN,      /* handled  */
+                       MOD_ACTION_RETURN,      /* invalid  */
+                       MOD_ACTION_RETURN,      /* userlock */
+                       MOD_ACTION_RETURN,      /* notfound */
+                       MOD_ACTION_RETURN,      /* noop     */
+                       MOD_ACTION_RETURN       /* updated  */
+               },
+               /* append */
+               {
+                       MOD_ACTION_RETURN,      /* reject   */
+                       1,                      /* fail     */
+                       MOD_ACTION_RETURN,      /* ok       */
+                       MOD_ACTION_RETURN,      /* handled  */
+                       MOD_ACTION_RETURN,      /* invalid  */
+                       MOD_ACTION_RETURN,      /* userlock */
+                       2,                      /* notfound */
+                       MOD_ACTION_RETURN,      /* noop     */
+                       MOD_ACTION_RETURN       /* updated  */
+               }
+       }
+#endif
 };
 
 
index 5ea8674..1f0f8f2 100644 (file)
@@ -84,7 +84,12 @@ static const section_type_value_t section_type_value[RLM_COMPONENT_COUNT] = {
        { "session",      "Session-Type",    PW_SESSION_TYPE },
        { "pre-proxy",    "Pre-Proxy-Type",  PW_PRE_PROXY_TYPE },
        { "post-proxy",   "Post-Proxy-Type", PW_POST_PROXY_TYPE },
-       { "post-auth",    "Post-Auth-Type",  PW_POST_AUTH_TYPE },
+       { "post-auth",    "Post-Auth-Type",  PW_POST_AUTH_TYPE }
+#ifdef WITH_COA
+       ,
+       { "recv-coa",     "Recv-CoA-Type",   PW_RECV_COA_TYPE },
+       { "send-coa",     "Send-CoA-Type",   PW_SEND_COA_TYPE }
+#endif
 };
 
 
@@ -1451,3 +1456,15 @@ int module_post_auth(int postauth_type, REQUEST *request)
 {
        return indexed_modcall(RLM_COMPONENT_POST_AUTH, postauth_type, request);
 }
+
+#ifdef WITH_COA
+int module_recv_coa(int recv_coa_type, REQUEST *request)
+{
+       return indexed_modcall(RLM_COMPONENT_RECV_COA, recv_coa_type, request);
+}
+
+int module_send_coa(int send_coa_type, REQUEST *request)
+{
+       return indexed_modcall(RLM_COMPONENT_SEND_COA, send_coa_type, request);
+}
+#endif
index 0d2df85..5805455 100644 (file)
@@ -966,11 +966,11 @@ int main(int argc, char **argv)
                packet_code = PW_STATUS_SERVER;
 
        } else if (strcmp(argv[2], "disconnect") == 0) {
-               if (server_port == 0) server_port = PW_POD_UDP_PORT;
+               if (server_port == 0) server_port = PW_COA_UDP_PORT;
                packet_code = PW_DISCONNECT_REQUEST;
 
        } else if (strcmp(argv[2], "coa") == 0) {
-               if (server_port == 0) server_port = PW_POD_UDP_PORT;
+               if (server_port == 0) server_port = PW_COA_UDP_PORT;
                packet_code = PW_COA_REQUEST;
 
        } else if (strcmp(argv[2], "auto") == 0) {
index c372cd8..7bd0c7c 100644 (file)
@@ -489,6 +489,12 @@ REQUEST *request_alloc_coa(REQUEST *request)
 {
        if (!request || request->coa) return NULL;
 
+       /*
+        *      Originate CoA requests only when necessary.
+        */
+       if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
+           (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
+
        request->coa = request_alloc_fake(request);
        request->coa->packet->code = 0; /* unknown, as of yet */
        request->coa->child_state = REQUEST_RUNNING;
index 91398fc..5e688f6 100644 (file)
@@ -166,5 +166,10 @@ module_t rlm_always = {
                always_return,          /* pre-proxy */
                always_return,          /* post-proxy */
                always_return           /* post-auth */
+#ifdef WITH_COA
+               ,
+               always_return,          /* recv-coa */
+               always_return           /* send-coa */
+#endif
        },
 };
index 01ebb7d..685fa72 100644 (file)
@@ -46,6 +46,46 @@ static const char *packet_codes[] = {
   "Password-Reject",
   "Accounting-Message",
   "Access-Challenge"
+  "Status-Server",
+  "Status-Client",
+  "14",
+  "15",
+  "16",
+  "17",
+  "18",
+  "19",
+  "20",
+  "Resource-Free-Request",
+  "Resource-Free-Response",
+  "Resource-Query-Request",
+  "Resource-Query-Response",
+  "Alternate-Resource-Reclaim-Request",
+  "NAS-Reboot-Request",
+  "NAS-Reboot-Response",
+  "28",
+  "Next-Passcode",
+  "New-Pin",
+  "Terminate-Session",
+  "Password-Expired",
+  "Event-Request",
+  "Event-Response",
+  "35",
+  "36",
+  "37",
+  "38",
+  "39",
+  "Disconnect-Request",
+  "Disconnect-ACK",
+  "Disconnect-NAK",
+  "CoA-Request",
+  "CoA-ACK",
+  "CoA-NAK",
+  "46",
+  "47",
+  "48",
+  "49",
+  "IP-Address-Allocate",
+  "IP-Address-Release"
 };
 
 
@@ -360,7 +400,7 @@ static int do_detail(void *instance, REQUEST *request, RADIUS_PACKET *packet,
                 *      Numbers, if not.
                 */
                if ((packet->code > 0) &&
-                   (packet->code <= PW_ACCESS_CHALLENGE)) {
+                   (packet->code < 52)) {
                        fprintf(outfp, "\tPacket-Type = %s\n",
                                packet_codes[packet->code]);
                } else {
@@ -515,6 +555,23 @@ static int detail_postauth(void *instance, REQUEST *request)
        return do_detail(instance,request,request->reply, FALSE);
 }
 
+#ifdef WITH_COA
+/*
+ *     Incoming CoA - write the detail files.
+ */
+static int detail_recv_coa(void *instance, REQUEST *request)
+{
+       return do_detail(instance,request,request->packet, FALSE);
+}
+
+/*
+ *     Outgoing CoA - write the detail files.
+ */
+static int detail_send_coa(void *instance, REQUEST *request)
+{
+       return do_detail(instance,request,request->reply, FALSE);
+}
+#endif
 
 /*
  *     Outgoing Access-Request to home server - write the detail files.
@@ -577,6 +634,10 @@ module_t rlm_detail = {
                detail_pre_proxy,       /* pre-proxy */
                detail_post_proxy,      /* post-proxy */
                detail_postauth         /* post-auth */
+#ifdef WITH_COA
+               , detail_recv_coa,
+               detail_send_coa
+#endif
        },
 };
 
index aa89c50..5a3e6a5 100644 (file)
@@ -67,6 +67,10 @@ static const int JRADIUS_checksimul   = 5;
 static const int JRADIUS_pre_proxy    = 6;
 static const int JRADIUS_post_proxy   = 7;
 static const int JRADIUS_post_auth    = 8;
+#ifdef WITH_COA
+static const int JRADIUS_recv_coa     = 9;
+static const int JRADIUS_send_coa     = 10;
+#endif
 
 #define LOG_PREFIX  "rlm_jradius: "
 #define MAX_HOSTS   4
@@ -1062,6 +1066,17 @@ static int jradius_post_auth(void *instance, REQUEST *request)
   return rlm_jradius_call(JRADIUS_post_auth, instance, request, 0);
 }
 
+#ifdef WITH_COA
+static int jradius_recv_coa(void *instance, REQUEST *request)
+{
+  return rlm_jradius_call(JRADIUS_recv_coa, instance, request, 0);
+}
+static int jradius_send_coa(void *instance, REQUEST *request)
+{
+  return rlm_jradius_call(JRADIUS_send_coa, instance, request, 0);
+}
+#endif
+
 static int jradius_detach(void *instance)
 {
   JRADIUS *inst = (JRADIUS *) instance;
@@ -1085,6 +1100,10 @@ module_t rlm_jradius = {
     jradius_pre_proxy,
     jradius_post_proxy,
     jradius_post_auth
+#ifdef WITH_COA
+    , jradius_recv_coa,
+    jradius_send_coa
+#endif
   },
 };
 
index eecde9e..bfdb516 100755 (executable)
@@ -288,5 +288,9 @@ module_t rlm_linelog = {
                do_linelog,     /* pre-proxy */
                do_linelog,     /* post-proxy */
                do_linelog      /* post-auth */
+#ifdef WITH_COA
+               , do_linelog,   /* recv-coa */
+               do_linelog      /* send-coa */
+#endif
        },
 };
index 1df206b..421e3e1 100644 (file)
@@ -69,6 +69,10 @@ typedef struct perl_inst {
        char    *func_pre_proxy;
        char    *func_post_proxy;
        char    *func_post_auth;
+#ifdef WITH_COA
+       char    *func_recv_coa;
+       char    *func_send_coa;
+#endif
        char    *xlat_name;
        char    *perl_flags;
        PerlInterpreter *perl;
@@ -105,6 +109,12 @@ static const CONF_PARSER module_config[] = {
          offsetof(PERL_INST,func_post_proxy), NULL, "post_proxy"},
        { "func_post_auth", PW_TYPE_STRING_PTR,
          offsetof(PERL_INST,func_post_auth), NULL, "post_auth"},
+#ifdef WITH_COA
+       { "func_recv_coa", PW_TYPE_STRING_PTR,
+         offsetof(PERL_INST,func_recv_coa), NULL, "recv_coa"},
+       { "func_send_coa", PW_TYPE_STRING_PTR,
+         offsetof(PERL_INST,func_send_coa), NULL, "send_coa"},
+#endif
        { "perl_flags", PW_TYPE_STRING_PTR,
          offsetof(PERL_INST,perl_flags), NULL, NULL},
        { "func_start_accounting", PW_TYPE_STRING_PTR,
@@ -868,6 +878,24 @@ static int perl_post_auth(void *instance, REQUEST *request)
        return rlmperl_call(instance, request,
                        ((PERL_INST *)instance)->func_post_auth);
 }
+#ifdef WITH_COA
+/*
+ *     Recv CoA request
+ */
+static int perl_recv_coa(void *instance, REQUEST *request)
+{
+       return rlmperl_call(instance, request,
+                       ((PERL_INST *)instance)->func_recv_coa);
+}
+/*
+ *     Send CoA request
+ */
+static int perl_send_coa(void *instance, REQUEST *request)
+{
+       return rlmperl_call(instance, request,
+                       ((PERL_INST *)instance)->func_send_coa);
+}
+#endif
 /*
  * Detach a instance give a chance to a module to make some internal setup ...
  */
@@ -970,5 +998,9 @@ module_t rlm_perl = {
                perl_pre_proxy,         /* pre-proxy */
                perl_post_proxy,        /* post-proxy */
                perl_post_auth          /* post-auth */
+#ifdef WITH_COA
+               , perl_recv_coa,
+               perl_send_coa
+#endif
        },
 };
index a79830d..8bc9c64 100644 (file)
@@ -1095,6 +1095,10 @@ const FR_NAME_NUMBER policy_component_names[] = {
        { "pre-proxy", RLM_COMPONENT_PRE_PROXY },
        { "post-proxy", RLM_COMPONENT_POST_PROXY },
        { "post-auth", RLM_COMPONENT_POST_AUTH },
+#ifdef WITH_COA
+       { "recv-coa", RLM_COMPONENT_RECV_COA },
+       { "send-coa", RLM_COMPONENT_SEND_COA },
+#endif
        { NULL, RLM_COMPONENT_COUNT }
 };
 
index b5f9d21..3c848d6 100644 (file)
@@ -189,6 +189,19 @@ static int policy_post_proxy(void *instance, REQUEST *request)
                                   "post-proxy");
 }
 
+#ifdef WITH_COA
+static int policy_recv_coa(void *instance, REQUEST *request)
+{
+       return rlm_policy_evaluate((rlm_policy_t *) instance, request,
+                                  "recv-coa");
+}
+static int policy_send_coa(void *instance, REQUEST *request)
+{
+       return rlm_policy_evaluate((rlm_policy_t *) instance, request,
+                                  "send-coa");
+}
+#endif
+
 /*
  *     The "free" functions are here, for no particular reason.
  */
@@ -322,5 +335,9 @@ module_t rlm_policy = {
                policy_pre_proxy,       /* pre-proxy */
                policy_post_proxy,      /* post-proxy */
                policy_post_auth        /* post-auth */
+#ifdef WITH_COA
+               , policy_recv_coa,
+               policy_send_coa
+#endif
        },
 };
index 2d1bbb3..13b7128 100644 (file)
@@ -31,18 +31,28 @@ def accounting(p):
   print p 
   return radiusd.RLM_MODULE_OK
 
-def preproxy(p):
-  print "*** preproxy ***"
+def pre_proxy(p):
+  print "*** pre_proxy ***"
   print p 
   return radiusd.RLM_MODULE_OK
 
-def postproxy(p):
-  print "*** postproxy ***"
+def post_proxy(p):
+  print "*** post_proxy ***"
   print p 
   return radiusd.RLM_MODULE_OK
 
-def postauth(p):
-  print "*** postauth ***"
+def post_auth(p):
+  print "*** post_auth ***"
+  print p 
+  return radiusd.RLM_MODULE_OK
+
+def recv_coa(p):
+  print "*** recv_coa ***"
+  print p 
+  return radiusd.RLM_MODULE_OK
+
+def send_coa(p):
+  print "*** send_coa ***"
   print p 
   return radiusd.RLM_MODULE_OK
 
index f0d4173..7030323 100644 (file)
@@ -54,6 +54,13 @@ struct rlm_python_t {
                preacct,
                accounting,
                checksimul,
+               pre_proxy,
+               post_proxy,
+               post_auth,
+#ifdef WITH_COA
+               recv_coa,
+               send_coa,
+#endif
                detach;
 };
 
@@ -77,6 +84,13 @@ static CONF_PARSER module_config[] = {
   A(preacct)
   A(accounting)
   A(checksimul)
+  A(pre_proxy)
+  A(post_proxy)
+  A(post_auth)
+#ifdef WITH_COA
+  A(recv_coa)
+  A(send_coa)
+#endif
   A(detach)
 
 #undef A
@@ -587,6 +601,13 @@ static int python_instantiate(CONF_SECTION *conf, void **instance)
         A(preacct);
         A(accounting);
         A(checksimul);
+        A(pre_proxy);
+        A(post_proxy);
+        A(post_auth);
+#ifdef WITH_COA
+        A(recv_coa);
+        A(send_coa);
+#endif
         A(detach);
 
 #undef A
@@ -628,6 +649,13 @@ A(authorize)
 A(preacct)
 A(accounting)
 A(checksimul)
+A(pre_proxy)
+A(post_proxy)
+A(post_auth)
+#ifdef WITH_COA
+A(recv_coa)
+A(send_coa)
+#endif
 
 #undef A
 
@@ -652,8 +680,12 @@ module_t rlm_python = {
                python_preacct,         /* preaccounting */
                python_accounting,      /* accounting */
                python_checksimul,      /* checksimul */
-               NULL,                   /* pre-proxy */
-               NULL,                   /* post-proxy */
-               NULL                    /* post-auth */
+               python_pre_proxy,       /* pre-proxy */
+               python_post_proxy,      /* post-proxy */
+               python_post_auth        /* post-auth */
+#ifdef WITH_COA
+               , python_recv_coa,
+               python_send_coa
+#endif
        }
 };
index ebaf34f..af01569 100644 (file)
@@ -47,6 +47,10 @@ typedef struct rlm_ruby_t {
     RLM_RUBY_STRUCT(preproxy);
     RLM_RUBY_STRUCT(postproxy);
     RLM_RUBY_STRUCT(postauth);
+#ifdef WITH_COA
+    RLM_RUBY_STRUCT(recvcoa);
+    RLM_RUBY_STRUCT(sendcoa);
+#endif
     RLM_RUBY_STRUCT(detach);
 
     char *scriptFile;
@@ -388,6 +392,10 @@ static int ruby_instantiate(CONF_SECTION *conf, void **instance) {
     RLM_RUBY_LOAD(preproxy);
     RLM_RUBY_LOAD(postproxy);
     RLM_RUBY_LOAD(postauth);
+#ifdef WITH_COA
+    RLM_RUBY_LOAD(recvcoa);
+    RLM_RUBY_LOAD(sendcoa);
+#endif
     RLM_RUBY_LOAD(detach);
 
     *instance = data;
@@ -411,6 +419,10 @@ RLM_RUBY_FUNC(checksimul)
 RLM_RUBY_FUNC(preproxy)
 RLM_RUBY_FUNC(postproxy)
 RLM_RUBY_FUNC(postauth)
+#ifdef WITH_COA
+RLM_RUBY_FUNC(recvcoa)
+RLM_RUBY_FUNC(sendcoa)
+#endif
 
 static int ruby_detach(void *instance) {
     int return_value;
@@ -455,5 +467,9 @@ module_t rlm_ruby = {
         ruby_preproxy, /* pre-proxy */
         ruby_postproxy, /* post-proxy */
         ruby_postauth /* post-auth */
+#ifdef WITH_COA
+       , ruby_recv_coa,
+       ruby_send_coa
+#endif
     },
 };