Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1 /* srp-log.h
      2  *
      3  * Copyright (c) 2020-2021 Apple Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     https://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  * This file contains the utilities that are used to print log that
     18  * redacts private information about the user, and function prototypes that
     19  * helps to create better logs.
     20  */
     21 
     22 
     23 #ifndef __SRP_LOG_H__
     24 #define __SRP_LOG_H__
     25 
     26 #include <stdint.h>
     27 #include <stdbool.h>
     28 
     29 #ifdef POSIX_BUILD
     30 #include <limits.h>
     31 #include <sys/param.h>
     32 #endif
     33 
     34 #ifdef __APPLE__
     35 #include <os/log.h> // For os_log related APIs
     36 #endif // #ifdef __APPLE__
     37 
     38 #ifdef DEBUG
     39 #    undef DEBUG
     40     // #define DEBUG_VERBOSE
     41 #endif
     42 
     43 // We always want this until we start shipping
     44 #define DEBUG_VERBOSE
     45 
     46 //======================================================================================================================
     47 // MARK: - Log Macros
     48 
     49 #ifdef FUZZING
     50 #    define OPENLOG(progname, consolep)
     51 #    define ERROR(fmt, ...)
     52 #    define INFO(fmt, ...)
     53 #    define DEBUG(fmt, ...)
     54 #    define FAULT(fmt, ...)
     55 #elif defined(THREAD_DEVKIT_ADK)
     56 
     57 #    include "srp-platform.h"
     58 
     59 #    define OPENLOG(progname, consolep) srp_openlog(option)
     60 #    define ERROR(fmt, ...)   srp_log_error(fmt, ##__VA_ARGS__)
     61 #    define INFO(fmt, ...)    srp_log_info(fmt, ##__VA_ARGS__)
     62 #    ifdef DEBUG_VERBOSE
     63 #        define DEBUG(fmt, ...) srp_log_debug(fmt, ##__VA_ARGS__)
     64 #    else
     65 #        define DEBUG(fmt, ...)
     66 #    endif // DEBUG VERBOSE
     67 #    define FAULT(fmt, ...) srp_log_error(fmt, ##__VA_ARGS__)
     68 #    define NO_CLOCK
     69 #else // ifdef THREAD_DEVKIT_ADK
     70 
     71 #    ifdef LOG_FPRINTF_STDERR
     72 void srp_log_timestamp(char *buf, size_t bufsize);
     73 extern bool srp_log_timestamp_relative;
     74 #        define OPENLOG(progname, consolep) do { (void)(consolep); (void)progname; } while (0)
     75 #        define SRP_LOG_TIME char srp_log_time_buf[32]; srp_log_timestamp(srp_log_time_buf, sizeof(srp_log_time_buf))
     76 #        define ERROR(fmt, ...) do { SRP_LOG_TIME; fprintf(stderr, "%s %s: " fmt "\n", srp_log_time_buf, __FUNCTION__, ##__VA_ARGS__); } while (0)
     77 #        define INFO(fmt, ...)  do { SRP_LOG_TIME; fprintf(stderr, "%s %s: " fmt "\n", srp_log_time_buf, __FUNCTION__, ##__VA_ARGS__); } while (0)
     78 #        ifdef DEBUG_VERBOSE
     79 #            ifdef IOLOOP_MACOS
     80                 int get_num_fds(void);
     81 #            endif // ifdef IOLOOP_MACOS
     82 #            define DEBUG(fmt, ...)  do { SRP_LOG_TIME; fprintf(stderr, "%s %s: " fmt "\n", srp_log_time_buf, __FUNCTION__, ##__VA_ARGS__); } while (0)
     83 #        else // ifdef DEBUG_VERBOSE
     84 #            define DEBUG(fmt, ...)
     85 #        endif
     86 #        define FAULT(fmt, ...) do { SRP_LOG_TIME; fprintf(stderr, "%s %s: " fmt "\n", srp_log_time_buf, __FUNCTION__, ##__VA_ARGS__); } while (0)
     87 #    else // ifdef LOG_FPRINTF_STDERR
     88 #        include <syslog.h>
     89 
     90         // Apple device always has OS_LOG support.
     91 #        ifdef __APPLE__
     92 #            define OS_LOG_ENABLED 1
     93 #            include <os/log.h>
     94 extern os_log_t global_os_log;
     95 
     96 
     97             // Define log level
     98 #            define LOG_TYPE_FAULT      OS_LOG_TYPE_FAULT
     99 #            define LOG_TYPE_ERROR      OS_LOG_TYPE_ERROR
    100 #            define LOG_TYPE_INFO       OS_LOG_TYPE_DEFAULT
    101 #            define LOG_TYPE_DEBUG      OS_LOG_TYPE_DEBUG
    102             // Define log macro
    103 #            define SRP_OS_LOG(component, type, format, ...) \
    104                 os_log_with_type((component), (type), ("%{public}s: " format), __FUNCTION__, ##__VA_ARGS__)
    105 
    106 #            define OPENLOG(progname, consolep) \
    107                 do { \
    108                     if (consolep) {                                         \
    109                         putenv("ACTIVITY_LOG_STDERR=1"); \
    110                     } \
    111                     (void)progname; \
    112                     global_os_log = os_log_create("com.apple.srp-mdns-proxy", "0"); \
    113                 } while (0)
    114 #            define FAULT(format, ...)  SRP_OS_LOG(global_os_log, LOG_TYPE_FAULT, format, ##__VA_ARGS__)
    115 #            define ERROR(format, ...)  SRP_OS_LOG(global_os_log, LOG_TYPE_ERROR, format, ##__VA_ARGS__)
    116 
    117 #            ifdef DEBUG_VERBOSE
    118 #                ifdef DEBUG_FD_LEAKS
    119                     int get_num_fds(void);
    120 #                    define INFO(format, ...) \
    121                         do { \
    122                             int foo = get_num_fds(); \
    123                             SRP_OS_LOG(global_os_log, LOG_TYPE_INFO, "%d " format, foo, ##__VA_ARGS__); \
    124                         } while(0)
    125 #                else // ifdef IOLOOP_MACOS
    126 #                    define INFO(format, ...) SRP_OS_LOG(global_os_log, LOG_TYPE_INFO, format, ##__VA_ARGS__)
    127 #                endif // ifdef IOLOOP_MACOS
    128 
    129 #                define DEBUG(format, ...) SRP_OS_LOG(global_os_log, LOG_TYPE_DEBUG, format, ##__VA_ARGS__)
    130 #            else // ifdef DEBUG_VERBOSE
    131 #                define INFO(format, ...) SRP_OS_LOG(global_os_log, LOG_TYPE_INFO, format, ##__VA_ARGS__)
    132 #                define DEBUG(format, ...)  do {} while(0)
    133 #            endif // ifdef DEBUG_VERBOSE
    134 #        else // ifdef __APPLE__
    135 #            define OS_LOG_ENABLED 0
    136 
    137 #            define OPENLOG(progname, consolep) openlog(progname, (consolep ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON)
    138 #            define FAULT(fmt, ...) syslog(LOG_CRIT, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
    139 #            define ERROR(fmt, ...) syslog(LOG_ERR, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
    140 
    141 #            ifdef DEBUG_VERBOSE
    142 #                ifdef DEBUG_FD_LEAKS
    143                     int get_num_fds(void);
    144 #                    define INFO(fmt, ...) \
    145                         do { \
    146                             int foo = get_num_fds(); \
    147                             syslog(LOG_INFO, "%s: %d " fmt, __FUNCTION__, foo, ##__VA_ARGS__); \
    148                         } while (0)
    149 #                else // ifdef IOLOOP_MACOS
    150 #                    define INFO(fmt, ...)  syslog(LOG_INFO, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
    151 #                endif // ifdef IOLOOP_MACOS
    152 #                define DEBUG(fmt, ...) syslog(LOG_DEBUG, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
    153 #            else // ifdef DEBUG_VERBOSE
    154 #                define INFO(fmt, ...)  syslog(LOG_INFO, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
    155 #                define DEBUG(fmt, ...) do {} while(0)
    156 #            endif // ifdef DEBUG_VERBOSE
    157 #        endif // ifdef __APPLE__
    158 #    endif // ifdef LOG_FPRINTF_STDERR
    159 #endif // ifdef THREAD_DEVKIT_ADK
    160 
    161 //======================================================================================================================
    162 // MARK: - Log Specifiers
    163 /**
    164  * With the logging routines defined above, the logging macros are defined to facilitate the log redaction enforced by
    165  * os_log on Apple platforms. By using the specifier "%{mask.hash}", the "<private>" text in the logs of customer device
    166  * would be shown as a hashing value, which could be used as a way to associate other SRP logs even if it's redacted.
    167  *
    168  * On Apple platforms, the current existing log routines will be defined as:
    169  * #define log_with_component_and_type(CATEGORY, LEVEL, format, ...) os_log_with_type((CATEGORY), (LEVEL), (format), \
    170  *                                                                      ##__VA_ARGS__)
    171  * #define ERROR(format, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_ERROR, format, ##__VA_ARGS__)
    172  * #define INFO(format, ...)   log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEFAULT, format, ##__VA_ARGS__)
    173  * #define DEBUG(format, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEBUG, format, ##__VA_ARGS__)
    174  * And to follow the same log level with os_log, FAULT() is defined.
    175  * #define FAULT(format, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_FAULT, format, ##__VA_ARGS__)
    176  * Therefore, all the previous logs would be put under OS_LOG_DEFAULT category.
    177  * FAULT level lof will be mapped to  LOG_TYPE_FAULT in os_log.
    178  * ERROR level log will be mapped to LOG_TYPE_ERROR in os_log.
    179  * INFO level log will be mapped to LOG_TYPE_DEFAULT in os_log.
    180  * DEBUG level log woll be mapped to LOG_TYPE_DEBUG in os_log.
    181  *
    182  * On platforms other than Apple, syslog will be used to write logs.
    183  * FAULT level lof will be mapped to  LOG_CRIT in syslog.
    184  * ERROR level log will be mapped to LOG_ERR in syslog.
    185  * INFO level log will be mapped to LOG_INFO in syslog.
    186  * DEBUG level log woll be mapped to LOG_DEBUG in syslog.
    187  *
    188  * The defined specifiers are:
    189  * String specifier:
    190  *      PUB_S_SRP: Use this in the format string when trying to log string and do not want it to be redacted.
    191  *      PRI_S_SRP: Use this when trying to log string and redact it to a hash string.
    192  *      Usage:
    193  *          INFO("Public string: " PUB_S_SRP, ", private string: " PRI_S_SRP, string_ptr, string_ptr);
    194  *
    195  * DNS name (with dns_label_t type) specifier:
    196  *      DNS_NAME_GEN_SRP: Always call this before logging DNS name.
    197  *      PUB_DNS_NAME_SRP: Use this in the format string when trying to log DNS name and do not want it to be redacted.
    198  *      PRI_DNS_NAME_SRP: Use this in the format string when trying to log DNS name and redact it to a hash string.
    199  *      DNS_NAME_PARAM_SRP: Always use DNS_NAME_PARAM_SRP in the paramter list.
    200  *      Usage:
    201  *          DNS_NAME_GEN_SRP(dns_name_ptr, dns_name_buf);
    202  *          INFO("Public DNS name: " PUB_DNS_NAME_SRP, ", private DNS name: " PRI_DNS_NAME_SRP,
    203  *              DNS_NAME_PARAM_SRP(dns_name_ptr, dns_name_buf), DNS_NAME_PARAM_SRP(dns_name_ptr, dns_name_buf));
    204  *
    205  * IPv4 address specifier (with in_addr * type or a pointer to uint8_t[4]):
    206  *      IPv4_ADDR_GEN_SRP: Always call this before logging IPv4 address.
    207  *      PUB_IPv4_ADDR_SRP: Use this in the format string when trying to log IPv4 address and do not want it to be
    208  *                         redacted.
    209  *      PRI_IPv4_ADDR_SRP: Use this in the format string when trying to log IPv4 address and redact it to a hash string.
    210  *      IPv4_ADDR_PARAM_SRP: Always use IPv4_ADDR_PARAM_SRP in the paramter list.
    211  *      Usage:
    212  *          IPv4_ADDR_GEN_SRP(in_addr_ptr_1, in_addr_buf_1);
    213  *          IPv4_ADDR_GEN_SRP(in_addr_ptr_2, in_addr_buf_2);
    214  *          INFO("Public IPv4 address: " PUB_IPv4_ADDR_SRP, ", private IPv4 address: " PRI_IPv4_ADDR_SRP,
    215  *              IPv4_ADDR_PARAM_SRP(in_addr_ptr_1, in_addr_buf_1), IPv4_ADDR_PARAM_SRP(in_addr_ptr_2, in_addr_buf_2));
    216  *
    217  * IPv6 address specifier (with in6_addr * type or a pointer to uint8_t[16]):
    218  *      IPv6_ADDR_GEN_SRP: Always call this before logging IPv6 address.
    219  *      PUB_IPv6_ADDR_SRP: Use this in the format string when trying to log IPv6 address and do not want it to be
    220  *                         redacted.
    221  *      PRI_IPv6_ADDR_SRP: Use this in the format string when trying to log IPv6 address and redact it to a hash string.
    222  *      IPv6_ADDR_PARAM_SRP: Always use IPv6_ADDR_PARAM_SRP in the paramter list.
    223  *      Usage:
    224  *          IPv6_ADDR_GEN_SRP(in6_addr_ptr_1, in6_addr_buf_1);
    225  *          IPv6_ADDR_GEN_SRP(in6_addr_ptr_2, in6_addr_buf_2);
    226  *          INFO("Public IPv6 address: " PUB_IPv6_ADDR_SRP, ", private IPv6 address: " PRI_IPv6_ADDR_SRP,
    227  *              IPv6_ADDR_PARAM_SRP(in6_addr_ptr_1, in6_addr_buf_1),
    228  *              IPv6_ADDR_PARAM_SRP(in6_addr_ptr_2, in6_addr_buf_2));
    229  *
    230  * Segmented IPv6  address specifier (with in6_addr * type or a pointer to uint8_t[16]):
    231  *      SEGMENTED_IPv6_ADDR_GEN_SRP: Always call this before logging segmented IPv6 address.
    232  *      PUB_SEGMENTED_IPv6_ADDR_SRP: Use this in the format string when trying to log segmented IPv6 address and do not
    233  *                                   want it to be redacted.
    234  *      PRI_SEGMENTED_IPv6_ADDR_SRP: Use this in the format string when trying to log segmented IPv6 address and redact
    235  *                                   it to a hash string.
    236  *      SEGMENTED_IPv6_ADDR_PARAM_SRP: Always use SEGMENTED_IPv6_ADDR_PARAM_SRP in the paramter list.
    237  *      Usage:
    238  *          SEGMENTED_IPv6_ADDR_GEN_SRP(in6_addr_ptr_1, in6_addr_buf_1);
    239  *          SEGMENTED_IPv6_ADDR_GEN_SRP(in6_addr_ptr_2, in6_addr_buf_2);
    240  *          INFO("Public IPv6 address: " PUB_SEGMENTED_IPv6_ADDR_SRP, ", private IPv6 address: "
    241  *               PRI_SEGMENTED_IPv6_ADDR_SRP, SEGMENTED_IPv6_ADDR_PARAM_SRP(in6_addr_ptr_1, in6_addr_buf_1),
    242  *               SEGMENTED_IPv6_ADDR_PARAM_SRP(in6_addr_ptr_2, in6_addr_buf_2));
    243  *      Note:
    244  *          Segmented IPv6 is prefered when logging IPv6 address in SRP, because the address is divided to: 48 bit
    245  *          prefix, 16 bit subnet, 64 bit host, which makes it easier to match the prefix even when log redaction is
    246  *          turned on and the address is hashed to a string.
    247  *
    248  * IPv6 prefix specifier (with a pointer to uint8_t[] array):
    249  *      IPv6_PREFIX_GEN_SRP: Always call this before logging IPv6 prefix (which is also segmented).
    250  *      PUB_IPv6_PREFIX_SRP: Use this in the format string when trying to log IPv6 prefix and do not want it to be
    251  *                           redacted.
    252  *      PRI_IPv6_PREFIX_SRP: Use this in the format string when trying to log IPv6 prefix and redact it to a hash
    253  *                           string.
    254  *      IPv6_PREFIX_PARAM_SRP: Always use IPv6_PREFIX_PARAM_SRP in the paramter list.
    255  *      Usage:
    256  *          IPv6_PREFIX_GEN_SRP(in6_prefix_ptr_1, sizeof(in6_prefix_1), in6_prefix_buf_1);
    257  *          IPv6_PREFIX_GEN_SRP(in6_prefix_ptr_2, sizeof(in6_prefix_2), in6_prefix_buf_2);
    258  *          INFO("Public IPv6 prefix: " PUB_IPv6_PREFIX_SRP, ", private IPv6 prefix: " PRI_IPv6_PREFIX_SRP,
    259  *              IPv6_PREFIX_PARAM_SRP(in6_prefix_buf_1), IPv6_PREFIX_PARAM_SRP(in6_prefix_buf_2));
    260  *
    261  * Mac address specifier (with a pointer to uint8_t[6] array):
    262  *      PUB_MAC_ADDR_SRP: Use this in the format string when trying to log Mac address and do not want it to be
    263  *                        redacted.
    264  *      PRI_MAC_ADDR_SRP: Use this in the format string when trying to log Mac address and redact it to a hash string.
    265  *      MAC_ADDR_PARAM_SRP: Always use MAC_ADDR_PARAM_SRP in the paramter list.
    266  *      Usage:
    267  *          INFO("Public MAC address: " PUB_MAC_ADDR_SRP, ", private MAC address: " PRI_MAC_ADDR_SRP,
    268  *              MAC_ADDR_PARAM_SRP(mac_addr), MAC_ADDR_PARAM_SRP(mac_addr));
    269  */
    270 
    271 // Helper macro to display if the correspoding IPv6 is ULA (Unique Local Address), LUA (Link Local Address)
    272 // or GUA (Global Unicast Address).
    273 // ULA starts with FC00::/7.
    274 // LUA starts with fe80::/10.
    275 // GUA starts with 2000::/3.
    276 #define IS_IPV6_ADDR_ULA(ADDR) ( ((ADDR)[0] & 0xFE) == 0xFC )
    277 #define IS_IPV6_ADDR_LUA(ADDR) ( ((ADDR)[0] == 0xFE) && ((uint8_t)(ADDR)[1] & 0xC0) == 0x80 )
    278 #define IS_IPV6_ADDR_GUA(ADDR) ( ((ADDR)[0] & 0xE0) == 0x20 )
    279 #define ADDRESS_RANGE_STR(ADDR) (                                                           \
    280                                     IS_IPV6_ADDR_ULA(ADDR) ?                                \
    281                                         "ULA: " :                                           \
    282                                         (( IS_IPV6_ADDR_LUA(ADDR) ) ?                       \
    283                                                 "LUA: " :                                   \
    284                                                 ( IS_IPV6_ADDR_GUA(ADDR) ? "GUA: " : "" ))  \
    285                                 )
    286 
    287 // Logging macros
    288 #if OS_LOG_ENABLED
    289     // Define log specifier
    290     // String
    291 #    define PUB_S_SRP "%{public}s"
    292 #    define PRI_S_SRP "%{private, mask.hash}s"
    293     // DNS name, when the pointer to DNS name is NULL, <NULL> will be logged.
    294 #    define DNS_NAME_GEN_SRP(NAME, BUF_NAME) \
    295         char BUF_NAME[DNS_MAX_NAME_SIZE_ESCAPED + 1]; \
    296         if (NAME != NULL) { \
    297             dns_name_print(NAME, BUF_NAME, sizeof(BUF_NAME)); \
    298         } else { \
    299             snprintf(BUF_NAME, sizeof(BUF_NAME), "<null>"); \
    300         }
    301 #    define PUB_DNS_NAME_SRP PUB_S_SRP
    302 #    define PRI_DNS_NAME_SRP PRI_S_SRP
    303 #    define DNS_NAME_PARAM_SRP(NAME, BUF) (BUF)
    304     // IP address
    305     // IPv4
    306 #    define IPv4_ADDR_GEN_SRP(ADDR, BUF_NAME) do {} while(0)
    307 #    define PUB_IPv4_ADDR_SRP "%{public, network:in_addr}.4P"
    308 #    define PRI_IPv4_ADDR_SRP "%{private, mask.hash, network:in_addr}.4P"
    309 #    define IPv4_ADDR_PARAM_SRP(ADDR, BUF) ((uint8_t *)ADDR)
    310     // IPv6
    311 #    define IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) do {} while(0)
    312 #    define PUB_IPv6_ADDR_SRP "%{public, network:in6_addr}.16P%{public}s"
    313 #    define PRI_IPv6_ADDR_SRP "%{public}s%{private, mask.hash, network:in6_addr}.16P"
    314 #    define IPv6_ADDR_PARAM_SRP(ADDR, BUF) ADDRESS_RANGE_STR((uint8_t *)(ADDR)), ((uint8_t *)(ADDR))
    315     // Segmented IPv6
    316     // Subnet part can always be public.
    317 #    define SEGMENTED_IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) do {} while(0)
    318 #    define PUB_SEGMENTED_IPv6_ADDR_SRP "{%{public, srp:in6_addr_segment}.6P%{public}s, " \
    319                                             "%{public, srp:in6_addr_segment}.2P, " \
    320                                             "%{public, srp:in6_addr_segment}.8P}"
    321 #    define PRI_SEGMENTED_IPv6_ADDR_SRP "{%{public}s%{private, mask.hash, srp:in6_addr_segment}.6P:" \
    322                                             "%{public, mask.hash, srp:in6_addr_segment}.2P:" \
    323                                             "%{private, mask.hash, srp:in6_addr_segment}.8P}"
    324 #    define SEGMENTED_IPv6_ADDR_PARAM_SRP(ADDR, BUF) ADDRESS_RANGE_STR((uint8_t *)(ADDR)), ((uint8_t *)(ADDR)), \
    325                                                         ((uint8_t *)(ADDR) + 6), ((uint8_t *)(ADDR) + 8)
    326     // MAC address
    327 #    define PUB_MAC_ADDR_SRP "%{public, srp:mac_addr}.6P"
    328 #    define PRI_MAC_ADDR_SRP "%{private, mask.hash, srp:mac_addr}.6P"
    329 #    define MAC_ADDR_PARAM_SRP(ADDR) ((uint8_t *)ADDR)
    330 
    331 #else // ifdef OS_LOG_ENABLED
    332     // When os_log is not available, all logs would be public.
    333     // Define log specifier
    334     // String
    335 #    define PUB_S_SRP "%s"
    336 #    define PRI_S_SRP PUB_S_SRP
    337     // DNS name, when the pointer to DNS name is NULL, <NULL> will be logged.
    338 #    if defined(MDNS_NO_STRICT) && (!MDNS_NO_STRICT)
    339 #        define SRP_LOG_STRNCPY_STRICT mdns_strlcpy
    340 #    else
    341 #        define SRP_LOG_STRNCPY_STRICT strlcpy
    342 #    endif
    343 #    ifdef IOLOOP_MACOS
    344 #        define SRP_LOG_STRNCPY SRP_LOG_STRNCPY_STRICT
    345 #    else
    346 #        define SRP_LOG_STRNCPY strncpy
    347 #    endif // IOLOOP_MACOS
    348 #    define DNS_NAME_GEN_SRP(NAME, BUF_NAME) \
    349         char BUF_NAME[DNS_MAX_NAME_SIZE_ESCAPED + 1]; \
    350         if (NAME != NULL) { \
    351             dns_name_print(NAME, BUF_NAME, sizeof(BUF_NAME)); \
    352         } else { \
    353             SRP_LOG_STRNCPY(BUF_NAME, "<null>", \
    354                             sizeof("<null>") < sizeof(BUF_NAME) ? sizeof("<null>") : sizeof(BUF_NAME)); \
    355         }
    356 #    define PUB_DNS_NAME_SRP "%s"
    357 #    define PRI_DNS_NAME_SRP PUB_DNS_NAME_SRP
    358 #    define DNS_NAME_PARAM_SRP(NAME, BUF) (BUF)
    359     // IP address
    360     // IPv4
    361 #    define IPv4_ADDR_GEN_SRP(ADDR, BUF_NAME) char BUF_NAME[INET_ADDRSTRLEN]; \
    362                                                     inet_ntop(AF_INET, ((uint8_t *)ADDR), BUF_NAME, sizeof(BUF_NAME))
    363 #    define PUB_IPv4_ADDR_SRP "%s"
    364 #    define PRI_IPv4_ADDR_SRP PUB_IPv4_ADDR_SRP
    365 #    define IPv4_ADDR_PARAM_SRP(ADDR, BUF) (BUF)
    366     // IPv6
    367 #    define IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) char BUF_NAME[INET6_ADDRSTRLEN]; \
    368                                                     inet_ntop(AF_INET6, ((uint8_t *)ADDR), BUF_NAME, sizeof(BUF_NAME))
    369 #    define PUB_IPv6_ADDR_SRP "%s%s"
    370 #    define PRI_IPv6_ADDR_SRP PUB_IPv6_ADDR_SRP
    371 #    define IPv6_ADDR_PARAM_SRP(ADDR, BUF) (BUF), ADDRESS_RANGE_STR((uint8_t *)ADDR)
    372     // Segmented IPv6
    373 #    define SEGMENTED_IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME)
    374 
    375 #    define PUB_SEGMENTED_IPv6_ADDR_SRP PUB_IPv6_ADDR_SRP
    376 #    define PRI_SEGMENTED_IPv6_ADDR_SRP PRI_IPv6_ADDR_SRP
    377 #    define SEGMENTED_IPv6_ADDR_PARAM_SRP(ADDR, BUF) IPv6_ADDR_PARAM_SRP(ADDR, BUF)
    378     // MAC address
    379 #    define PUB_MAC_ADDR_SRP "%02x:%02x:%02x:%02x:%02x:%02x"
    380 #    define PRI_MAC_ADDR_SRP PUB_MAC_ADDR_SRP
    381 #    define MAC_ADDR_PARAM_SRP(ADDR) ((uint8_t *)ADDR)[0], ((uint8_t *)ADDR)[1], ((uint8_t *)ADDR)[2], \
    382                                         ((uint8_t *)ADDR)[3], ((uint8_t *)ADDR)[4], ((uint8_t *)ADDR)[5]
    383 
    384 #endif // ifdef OS_LOG_ENABLED
    385 
    386 // IPv6 ULA 48-bit prefix
    387 #define IPv6_PREFIX_GEN_SRP(PREFIX, PREFIX_LEN, BUF_NAME) \
    388     struct in6_addr _in6_addr_##BUF_NAME##_full_addr = {0}; \
    389     memcpy(_in6_addr_##BUF_NAME##_full_addr.s6_addr, (PREFIX), \
    390         MIN(sizeof(_in6_addr_##BUF_NAME##_full_addr.s6_addr), (PREFIX_LEN))); \
    391     SEGMENTED_IPv6_ADDR_GEN_SRP(_in6_addr_##BUF_NAME##_full_addr.s6_addr, BUF_NAME);
    392 #define PUB_IPv6_PREFIX_SRP PUB_SEGMENTED_IPv6_ADDR_SRP
    393 #define PRI_IPv6_PREFIX_SRP PRI_SEGMENTED_IPv6_ADDR_SRP
    394 #define IPv6_PREFIX_PARAM_SRP(BUF_NAME) SEGMENTED_IPv6_ADDR_PARAM_SRP(_in6_addr_##BUF_NAME##_full_addr.s6_addr, \
    395                                             BUF_NAME)
    396 
    397 //======================================================================================================================
    398 // MARK: - To String Helpers
    399 
    400 /*!
    401  *  @brief
    402  *      Convert DNS question class to its corresponding text description.
    403  *
    404  *  @param qclass
    405  *      The DNS question class value in the DNS message.
    406  *
    407  *  @result
    408  *      The corresponding text description for the given DNS question class if it is valid. Otherwise, an error string will be returned.
    409  */
    410 const char *
    411 dns_qclass_to_string(uint16_t qclass);
    412 
    413 /*!
    414  *  @brief
    415  *      Convert DNS record type to its corresponding text description.
    416  *
    417  *  @param rrtype
    418  *      The DNS record type value of the DNS record.
    419  *
    420  *  @result
    421  *      The corresponding text description for the given DNS record type if it is valid. Otherwise, an error string will be returned.
    422  */
    423 const char *
    424 dns_rrtype_to_string(uint16_t rrtype);
    425 
    426 #endif // __SRP_LOG_H__
    427 
    428 // Local Variables:
    429 // mode: C
    430 // tab-width: 4
    431 // c-file-style: "bsd"
    432 // c-basic-offset: 4
    433 // fill-column: 108
    434 // indent-tabs-mode: nil
    435 // End:
    436