|
14 | 14 | #include <unistd.h> |
15 | 15 | #include <sys/utsname.h> |
16 | 16 | #include <sys/sysinfo.h> |
| 17 | +#include <netdb.h> |
| 18 | +#include <sys/socket.h> |
| 19 | +#include <arpa/inet.h> |
| 20 | +#include <string.h> |
17 | 21 |
|
18 | 22 | bool total_opened_handle(int *total_handles); |
| 23 | +static bool get_dns_domain_name(const char *hostname, char *domain_name, size_t domain_size); |
19 | 24 | void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); |
20 | 25 |
|
21 | 26 | bool total_opened_handle(int *total_handles) |
@@ -57,6 +62,120 @@ bool total_opened_handle(int *total_handles) |
57 | 62 | return true; |
58 | 63 | } |
59 | 64 |
|
| 65 | +/* |
| 66 | + * get_dns_domain_name |
| 67 | + * |
| 68 | + * Attempts to retrieve the DNS domain name using multiple fallback strategies: |
| 69 | + * 1. Try DNS resolution to get FQDN, then extract domain |
| 70 | + * 2. Read from /etc/resolv.conf (domain or search directive) |
| 71 | + * 3. Fallback to getdomainname() with validation |
| 72 | + * |
| 73 | + * Returns true if domain name was found, false otherwise |
| 74 | + */ |
| 75 | +static bool get_dns_domain_name(const char *hostname, char *domain_name, size_t domain_size) |
| 76 | +{ |
| 77 | + struct addrinfo hints, *info = NULL; |
| 78 | + bool found = false; |
| 79 | + char *dot_pos = NULL; |
| 80 | + |
| 81 | + memset(domain_name, 0, domain_size); |
| 82 | + |
| 83 | + /* Strategy 1: Try DNS resolution to get FQDN */ |
| 84 | + memset(&hints, 0, sizeof(hints)); |
| 85 | + hints.ai_family = AF_UNSPEC; |
| 86 | + hints.ai_socktype = SOCK_STREAM; |
| 87 | + hints.ai_flags = AI_CANONNAME; |
| 88 | + |
| 89 | + if (getaddrinfo(hostname, NULL, &hints, &info) == 0 && info != NULL) |
| 90 | + { |
| 91 | + if (info->ai_canonname != NULL) |
| 92 | + { |
| 93 | + /* Look for first dot to extract domain from FQDN */ |
| 94 | + dot_pos = strchr(info->ai_canonname, '.'); |
| 95 | + if (dot_pos != NULL && strlen(dot_pos + 1) > 0) |
| 96 | + { |
| 97 | + /* Copy domain part (after first dot) */ |
| 98 | + snprintf(domain_name, domain_size, "%s", dot_pos + 1); |
| 99 | + found = true; |
| 100 | + ereport(DEBUG1, (errmsg("domain name extracted from FQDN: %s", domain_name))); |
| 101 | + } |
| 102 | + } |
| 103 | + freeaddrinfo(info); |
| 104 | + } |
| 105 | + |
| 106 | + /* Strategy 2: If DNS failed, try reading from /etc/resolv.conf */ |
| 107 | + if (!found) |
| 108 | + { |
| 109 | + FILE *resolv_file = fopen("/etc/resolv.conf", "r"); |
| 110 | + if (resolv_file != NULL) |
| 111 | + { |
| 112 | + char *line_buf = NULL; |
| 113 | + size_t line_buf_size = 0; |
| 114 | + ssize_t line_size; |
| 115 | + |
| 116 | + while ((line_size = getline(&line_buf, &line_buf_size, resolv_file)) >= 0) |
| 117 | + { |
| 118 | + char *trimmed = str_trim(line_buf); |
| 119 | + |
| 120 | + /* Check for "domain" directive (preferred) */ |
| 121 | + if (strncmp(trimmed, "domain", 6) == 0) |
| 122 | + { |
| 123 | + char *domain_val = str_trim(trimmed + 6); |
| 124 | + if (strlen(domain_val) > 0) |
| 125 | + { |
| 126 | + snprintf(domain_name, domain_size, "%s", domain_val); |
| 127 | + found = true; |
| 128 | + ereport(DEBUG1, (errmsg("domain name from /etc/resolv.conf (domain): %s", domain_name))); |
| 129 | + break; |
| 130 | + } |
| 131 | + } |
| 132 | + /* Check for "search" directive (fallback) */ |
| 133 | + else if (!found && strncmp(trimmed, "search", 6) == 0) |
| 134 | + { |
| 135 | + char *search_val = str_trim(trimmed + 6); |
| 136 | + /* Take first domain from search list */ |
| 137 | + char *space = strchr(search_val, ' '); |
| 138 | + if (space != NULL) |
| 139 | + *space = '\0'; |
| 140 | + |
| 141 | + if (strlen(search_val) > 0) |
| 142 | + { |
| 143 | + snprintf(domain_name, domain_size, "%s", search_val); |
| 144 | + found = true; |
| 145 | + ereport(DEBUG1, (errmsg("domain name from /etc/resolv.conf (search): %s", domain_name))); |
| 146 | + } |
| 147 | + } |
| 148 | + } |
| 149 | + |
| 150 | + if (line_buf != NULL) |
| 151 | + free(line_buf); |
| 152 | + fclose(resolv_file); |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + /* Strategy 3: Last resort - try getdomainname() with validation */ |
| 157 | + if (!found) |
| 158 | + { |
| 159 | + char nis_domain[256]; |
| 160 | + memset(nis_domain, 0, sizeof(nis_domain)); |
| 161 | + |
| 162 | + if (getdomainname(nis_domain, sizeof(nis_domain)) == 0) |
| 163 | + { |
| 164 | + /* Validate that it's not empty or "(none)" */ |
| 165 | + if (strlen(nis_domain) > 0 && |
| 166 | + strcmp(nis_domain, "(none)") != 0 && |
| 167 | + strcmp(nis_domain, "localdomain") != 0) |
| 168 | + { |
| 169 | + snprintf(domain_name, domain_size, "%s", nis_domain); |
| 170 | + found = true; |
| 171 | + ereport(DEBUG1, (errmsg("domain name from getdomainname(): %s", domain_name))); |
| 172 | + } |
| 173 | + } |
| 174 | + } |
| 175 | + |
| 176 | + return found; |
| 177 | +} |
| 178 | + |
60 | 179 | void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) |
61 | 180 | { |
62 | 181 | struct utsname uts; |
@@ -103,21 +222,25 @@ void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) |
103 | 222 |
|
104 | 223 | /* Function used to get the host name of the system */ |
105 | 224 | if (gethostname(host_name, sizeof(host_name)) != 0) |
| 225 | + { |
106 | 226 | ereport(DEBUG1, |
107 | 227 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
108 | 228 | errmsg("error while getting host name"))); |
109 | | - |
110 | | - /* Function used to get the domain name of the system */ |
111 | | - if (getdomainname(domain_name, sizeof(domain_name)) != 0) |
112 | | - ereport(DEBUG1, |
113 | | - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
114 | | - errmsg("error while getting domain name"))); |
115 | | - |
116 | | - /*If hostname or domain name is empty, set the value to NULL */ |
117 | | - if (strlen(host_name) == 0) |
118 | 229 | nulls[Anum_host_name] = true; |
119 | | - if (strlen(domain_name) == 0) |
| 230 | + } |
| 231 | + else if (strlen(host_name) == 0) |
| 232 | + { |
| 233 | + nulls[Anum_host_name] = true; |
| 234 | + } |
| 235 | + |
| 236 | + /* Get DNS domain name using multiple fallback strategies */ |
| 237 | + if (!get_dns_domain_name(host_name, domain_name, sizeof(domain_name))) |
| 238 | + { |
| 239 | + /* All strategies failed, set to NULL */ |
120 | 240 | nulls[Anum_domain_name] = true; |
| 241 | + ereport(DEBUG1, |
| 242 | + (errmsg("unable to determine domain name from any source"))); |
| 243 | + } |
121 | 244 |
|
122 | 245 | os_info_file = fopen(OS_INFO_FILE_NAME, "r"); |
123 | 246 |
|
|
0 commit comments