18
18
19
19
/**
20
20
* Sets up and returns a Logger instance.
21
- *
22
- * @param string $logFilePath Full path to the log file.
23
- * @param string $channelName Name of the log channel (optional).
24
- * @return Logger
25
21
*/
26
22
function setupLogger ($ logFilePath , $ channelName = 'app ' ) {
27
- // Create a log channel
28
23
$ log = new Logger ($ channelName );
29
-
30
- // Set up the console handler
31
24
$ consoleHandler = new StreamHandler ('php://stdout ' , Logger::DEBUG );
32
25
$ consoleFormatter = new LineFormatter (
33
26
"[%datetime%] %channel%.%level_name%: %message% %context% %extra% \n" ,
34
- "Y-m-d H:i:s.u " , // Date format
35
- true , // Allow inline line breaks
36
- true // Ignore empty context and extra
27
+ "Y-m-d H:i:s.u " ,
28
+ true ,
29
+ true
37
30
);
38
31
$ consoleHandler ->setFormatter ($ consoleFormatter );
39
32
$ log ->pushHandler ($ consoleHandler );
40
33
41
- // Set up the file handler
42
34
$ fileHandler = new RotatingFileHandler ($ logFilePath , 0 , Logger::DEBUG );
43
35
$ fileFormatter = new LineFormatter (
44
36
"[%datetime%] %channel%.%level_name%: %message% %context% %extra% \n" ,
45
- "Y-m-d H:i:s.u " // Date format
37
+ "Y-m-d H:i:s.u "
46
38
);
47
39
$ fileHandler ->setFormatter ($ fileFormatter );
48
40
$ log ->pushHandler ($ fileHandler );
@@ -57,30 +49,24 @@ function isIpWhitelisted($ip, $pdo) {
57
49
return $ count > 0 ;
58
50
}
59
51
60
- // Function to update the permitted IPs from the database
61
52
function updatePermittedIPs ($ pool , $ permittedIPsTable ) {
62
53
$ pdo = $ pool ->get ();
63
54
$ query = "SELECT ip_address FROM whitelist " ;
64
55
$ stmt = $ pdo ->query ($ query );
65
56
$ permittedIPs = $ stmt ->fetchAll (PDO ::FETCH_COLUMN , 0 );
66
57
$ pool ->put ($ pdo );
67
58
68
- // Manually clear the table by removing each entry
69
59
foreach ($ permittedIPsTable as $ key => $ value ) {
70
60
$ permittedIPsTable ->del ($ key );
71
61
}
72
62
73
- // Insert new values
74
63
foreach ($ permittedIPs as $ ip ) {
75
64
$ permittedIPsTable ->set ($ ip , ['ip_address ' => $ ip ]);
76
65
}
77
66
}
78
67
79
68
/**
80
- * Load and save zone files.
81
- *
82
- * @param Badcow\DNS\Zone $zone
83
- * @throws Exception if unable to save the zone file
69
+ * Save the zone file.
84
70
*/
85
71
function saveZone ($ zone ) {
86
72
$ zoneDir = $ _ENV ['BIND9_ZONE_DIR ' ];
@@ -93,80 +79,53 @@ function saveZone($zone) {
93
79
}
94
80
95
81
/**
96
- * Backup the configuration file before modifying.
97
- *
98
- * @param string $configFile
99
- * @throws Exception if unable to create a backup
82
+ * Backup the configuration file.
100
83
*/
101
84
function backupConfigFile (string $ configFile ): void {
102
85
$ backupFile = $ configFile . '.bak. ' . date ('YmdHis ' );
103
-
104
86
if (!copy ($ configFile , $ backupFile )) {
105
87
throw new Exception ("Failed to create backup of $ configFile " );
106
88
}
107
89
}
108
90
109
91
/**
110
- * Remove a zone block from named.conf.local
111
- *
112
- * @param string $zoneName
113
- * @throws Exception if unable to modify the config file or zone block not found
92
+ * Remove a zone block from named.conf.local.
114
93
*/
115
94
function removeZoneFromConfig (string $ zoneName ): void {
116
95
$ configFile = $ _ENV ['BIND9_CONF_FILE ' ];
117
-
118
- // Backup the config file before modifying
119
96
backupConfigFile ($ configFile );
120
-
121
- // Read the current config file
122
97
$ configContent = file_get_contents ($ configFile );
123
98
if ($ configContent === false ) {
124
99
throw new Exception ("Unable to read $ configFile " );
125
100
}
126
-
127
- // Define a regex pattern to match the zone block
128
101
$ pattern = '/zone\s+" ' .preg_quote ($ zoneName , '/ ' ).'"\s*\{[^}]*\};\n?/i ' ;
129
-
130
- // Check if the zone block exists
131
102
if (!preg_match ($ pattern , $ configContent )) {
132
103
throw new Exception ("Zone block for ' $ zoneName' not found in $ configFile " );
133
104
}
134
-
135
- // Remove the zone block
136
105
$ newConfigContent = preg_replace ($ pattern , '' , $ configContent , 1 );
137
-
138
106
if ($ newConfigContent === null ) {
139
107
throw new Exception ("Error occurred while removing the zone block " );
140
108
}
141
-
142
- // Write the updated config back to the file
143
109
if (file_put_contents ($ configFile , $ newConfigContent , LOCK_EX ) === false ) {
144
110
throw new Exception ("Unable to write to $ configFile " );
145
111
}
146
112
}
147
113
148
114
/**
149
- * Append a new zone block to named.conf.local
150
- *
151
- * @param string $zoneName
152
- * @param string $zoneFilePath
153
- * @throws Exception if unable to write to the config file
115
+ * Append a new zone block to named.conf.local.
154
116
*/
155
117
function addZoneToConfig (string $ zoneName , string $ zoneFilePath ): void {
156
118
$ configFile = $ _ENV ['BIND9_CONF_FILE ' ];
157
-
158
- // Backup the config file before modifying
159
119
backupConfigFile ($ configFile );
160
-
161
- // Define the zone block
162
120
$ zoneBlock = "\nzone \"$ zoneName \" { \n type master; \n file \"$ zoneFilePath \"; \n}; \n" ;
163
-
164
- // Append the zone block to the config file
165
121
if (file_put_contents ($ configFile , $ zoneBlock , FILE_APPEND | LOCK_EX ) === false ) {
166
122
throw new Exception ("Unable to write to $ configFile " );
167
123
}
168
124
}
169
125
126
+ /**
127
+ * Load a zone file.
128
+ */
170
129
function loadZone ($ zoneName ) {
171
130
$ zoneDir = $ _ENV ['BIND9_ZONE_DIR ' ];
172
131
$ zoneFile = "$ zoneDir/ $ zoneName.zone " ;
@@ -178,23 +137,24 @@ function loadZone($zoneName) {
178
137
return $ zone ;
179
138
}
180
139
140
+ /**
141
+ * Reload BIND9 configuration and notify slaves.
142
+ */
181
143
function reloadBIND9 () {
182
- // Reload BIND9 configuration
183
144
exec ('sudo rndc reload ' , $ output , $ return_var );
184
145
if ($ return_var !== 0 ) {
185
146
throw new Exception ("Failed to reload BIND9: " . implode ("\n" , $ output ));
186
147
}
187
-
188
- // Notify slave servers
189
148
exec ('sudo rndc notify ' , $ notify_output , $ notify_return_var );
190
149
if ($ notify_return_var !== 0 ) {
191
150
throw new Exception ("Failed to notify slave servers: " . implode ("\n" , $ notify_output ));
192
151
}
193
152
}
194
153
195
- // Authentication Middleware
154
+ /**
155
+ * Authentication middleware.
156
+ */
196
157
function authenticate ($ request , $ pdo , $ log ) {
197
- // Get the token from the Authorization header
198
158
$ authHeader = $ request ->header ['authorization ' ] ?? '' ;
199
159
if (!$ authHeader ) {
200
160
return false ;
@@ -206,13 +166,11 @@ function authenticate($request, $pdo, $log) {
206
166
}
207
167
208
168
$ token = $ authParts [1 ];
209
-
210
169
if (!$ token ) {
211
170
return false ;
212
171
}
213
172
214
173
try {
215
- // Prepare statement to fetch session securely
216
174
$ stmt = $ pdo ->prepare ('
217
175
SELECT s.user_id, u.username, s.expires_at, s.ip_address, s.user_agent
218
176
FROM sessions s
@@ -224,32 +182,24 @@ function authenticate($request, $pdo, $log) {
224
182
$ session = $ stmt ->fetch (PDO ::FETCH_ASSOC );
225
183
226
184
if (!$ session ) {
227
- // Invalid token
228
185
return false ;
229
186
}
230
-
231
- // Check if the session has expired
232
187
if (strtotime ($ session ['expires_at ' ]) < time ()) {
233
- // Session has expired
234
188
return false ;
235
189
}
236
-
237
- // Authentication successful
238
- // Return user information (e.g., user ID and username)
239
190
return [
240
191
'user_id ' => $ session ['user_id ' ],
241
192
'username ' => $ session ['username ' ]
242
193
];
243
194
} catch (Exception $ e ) {
244
- // Log the exception internally without exposing details to the client
245
195
$ log ->error ('Authentication error: ' . $ e ->getMessage ());
246
196
return false ;
247
197
}
248
198
}
249
199
250
200
function generateInitialSerialNumber () {
251
- $ currentDate = date ('Ymd ' ); // YYYYMMDD
252
- return $ currentDate . '01 ' ; // Initial serial number
201
+ $ currentDate = date ('Ymd ' );
202
+ return $ currentDate . '01 ' ;
253
203
}
254
204
255
205
function getCurrentSerialNumber ($ pdo , $ domainName ) {
@@ -267,29 +217,35 @@ function insertInitialSerialNumber($pdo, $domainName) {
267
217
268
218
function updateSerialNumber ($ pdo , $ domainName ) {
269
219
$ currentSerial = getCurrentSerialNumber ($ pdo , $ domainName );
270
- $ currentDate = date ('Ymd ' ); // YYYYMMDD
271
-
272
- // Extract date and change number (NN) from current serial number
220
+ $ currentDate = date ('Ymd ' );
273
221
$ serialDate = substr ($ currentSerial , 0 , 8 );
274
222
$ changeNumber = (int )substr ($ currentSerial , 8 , 2 );
275
223
276
224
if ($ serialDate === $ currentDate ) {
277
- // Increment the change number
278
225
$ changeNumber ++;
279
- if ($ changeNumber < 10 ) {
280
- $ changeNumber = '0 ' . $ changeNumber ; // Ensure it is two digits
281
- }
226
+ $ changeNumber = str_pad ($ changeNumber , 2 , '0 ' , STR_PAD_LEFT );
282
227
} else {
283
- // New date, reset change number to '01'
284
228
$ changeNumber = '01 ' ;
285
229
}
286
230
287
- // Construct new serial number
288
231
$ newSerial = $ currentDate . $ changeNumber ;
289
-
290
- // Update serial number in the database
291
232
$ stmt = $ pdo ->prepare ('UPDATE zones SET current_soa = :serial_number WHERE domain_name = :domain_name ' );
292
233
$ stmt ->execute ([':serial_number ' => $ newSerial , ':domain_name ' => $ domainName ]);
293
-
294
234
return $ newSerial ;
295
- }
235
+ }
236
+
237
+ /**
238
+ * Update the SOA record in the zone by updating its serial number.
239
+ */
240
+ function updateZoneSoa ($ zone , $ zoneName , $ pdo ) {
241
+ $ newSerial = updateSerialNumber ($ pdo , $ zoneName );
242
+ foreach ($ zone ->getResourceRecords () as $ record ) {
243
+ if (strtoupper ($ record ->getType ()) === 'SOA ' ) {
244
+ $ soaRdata = $ record ->getRdata ();
245
+ $ soaRdata ->setSerial ($ newSerial );
246
+ $ record ->setRdata ($ soaRdata );
247
+ break ;
248
+ }
249
+ }
250
+ saveZone ($ zone );
251
+ }
0 commit comments