Cacti Dell R750 iDRAC Temperature

I’ve setup a template to monitor a Dell R750 server via configured SNMP access on iDRAC.

My server has only two CPU (Intel Xeon Gold 6338N). I did not create this as a robust type of template, where it will walk all CPUs. Eventually I’ll get to that, but for now each data source OID is set manually.

Here are the OIDs:

OIDDescription
.1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.1CPU1 Temp
.1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.2CPU2 Temp
.1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.3System Board Inlet Temp
.1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.4System Board Exhaust Temp

Download

PHP real-time system command output

Throwing some notes here for me to remember on having PHP not buffer the output of a long running process so that it provides realtime output to the browser. I tinkered with SSE options and even AJAX/jQuery, but I finally got this to somewhat work reliably. Note that these notes are tested on PHP 8.1 and Apache 2.4.

.htaccess

This is required to disable buffering at the server level. Make sure to have mod_rewrite enabled.

RewriteRule ^(.*)$ $1 [NS,E=no-gzip:1,E=dont-vary:1]

PHP

<?php
ob_implicit_flush(true);
ob_end_flush();

echo 'Begin', PHP_EOL;


for ($i = 0; $i < 10; $i++) {
echo $i, PHP_EOL;
ob_flush();
flush();

sleep(1);
}

echo 'Done', PHP_EOL;

A command example using passthru

<?php
ob_implicit_flush(true);
ob_end_flush();
echo '<PRE>';
echo 'BEGIN',PHP_EOL;
passthru('ping -c 5 8.8.8.8');
ob_flush();
flush();
echo 'DONE', PHP_EOL;
?>

A Port Scanner in C

The following port scanner C code checks approximately 65535 ports in about 15 seconds on-network.

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/wait.h>

#define MAX_PORTS 65535
#define MAX_SOCKETS 1023

// gcc -o portscanner portscanner.c

int scan_port(const char* host, int port) {
    struct sockaddr_in server;
    int sock;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("socket");
        return -1;
    }

    server.sin_addr.s_addr = inet_addr(host);
    server.sin_family = AF_INET;
    server.sin_port = htons(port);

    int flags = fcntl(sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flags | O_NONBLOCK);

    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == -1) {
        if (errno != EINPROGRESS) {
            perror("connect");
            return -1;
        }
    }

    fd_set fdset;
    struct timeval tv;

    FD_ZERO(&fdset);
    FD_SET(sock, &fdset);

    tv.tv_sec = 0;
    tv.tv_usec = 200000;  // Timeout of 200ms

    int select_ret = select(sock + 1, NULL, &fdset, NULL, &tv);

    if (select_ret == -1) {
        perror("select");
        return -1;
    }
    else if (select_ret == 0) {
        close(sock);
        return 0;
    }

    // Connection successful, port is open
    close(sock);
    return 1;
}

void scan_ports(const char* host, int start_port, int end_port) {
    int num_sockets = 0;
    int port;

    for (port = start_port; port <= end_port; port++) {
        pid_t pid = fork();
        if (pid == -1) {
            perror("fork");
            exit(EXIT_FAILURE);
        } else if (pid == 0) {
            // Child process
            int result = scan_port(host, port);
            if (result == 1) {
                printf("Port %d is open\n", port);
            }
            exit(EXIT_SUCCESS);
        } else {
            // Parent process
            num_sockets++;
            if (num_sockets >= MAX_SOCKETS) {
                wait(NULL);
                num_sockets--;
            }
        }
    }
}

int main(int argc, char* argv[]) {
    if (argc < 3 || argc > 4) {
        printf("Usage: %s <host> <port/start_port> [end_port]\n", argv[0]);
        return 1;
    }

    const char* host = argv[1];
    int start_port = atoi(argv[2]);
    int end_port;

    if (argc == 4) {
        end_port = atoi(argv[3]);
        if (start_port < 1 || start_port > MAX_PORTS || end_port < 1 || end_port > MAX_PORTS || start_port > end_port) {
            printf("Invalid port range.\n");
            return 1;
        }
    } else {
        end_port = start_port;
        if (start_port < 1 || start_port > MAX_PORTS) {
            printf("Invalid port.\n");
            return 1;
        }
    }

    printf("Scanning ports %d to %d on host %s...\n", start_port, end_port, host);
    scan_ports(host, start_port, end_port);
    return 0;
}

Here is a Windows version; it is much slower.

// CFLAGS="-static-libgcc -static-libstdc++ -03"
// i686-w64-mingw32-gcc -o portscanner.exe portscanner_win32.c -lws2_32

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <process.h>

#pragma comment(lib, "ws2_32.lib")

#define MAX_PORTS 65535

typedef struct {
    const char* host;
    int start_port;
    int end_port;
} ScanParams;

int scan_port(const char* host, int port) {
    WSADATA wsaData;
    SOCKET sock;
    struct sockaddr_in server;

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        perror("WSAStartup");
        return -1;
    }

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        perror("socket");
        WSACleanup();
        return -1;
    }

    server.sin_addr.s_addr = inet_addr(host);
    server.sin_family = AF_INET;
    server.sin_port = htons(port);

    u_long nonblocking = 1;
    if (ioctlsocket(sock, FIONBIO, &nonblocking) != 0) {
        perror("ioctlsocket");
        closesocket(sock);
        WSACleanup();
        return -1;
    }

    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
        int error = WSAGetLastError();
        if (error != WSAEWOULDBLOCK) {
            perror("connect");
            closesocket(sock);
            WSACleanup();
            return -1;
        }
    }

    fd_set fdset;
    struct timeval tv;

    FD_ZERO(&fdset);
    FD_SET(sock, &fdset);

    tv.tv_sec = 0;
    tv.tv_usec = 200000;  // Timeout of 200ms

    int select_ret = select(0, NULL, &fdset, NULL, &tv);

    if (select_ret == SOCKET_ERROR) {
        perror("select");
        closesocket(sock);
        WSACleanup();
        return -1;
    } else if (select_ret == 0) {
        closesocket(sock);
        WSACleanup();
        return 0;
    }

    // Connection successful, port is open
    closesocket(sock);
    WSACleanup();
    return 1;
}

unsigned int __stdcall scan_ports_thread(void* params) {
    ScanParams* scanParams = (ScanParams*)params;
    const char* host = scanParams->host;
    int start_port = scanParams->start_port;
    int end_port = scanParams->end_port;
    int port;

    for (port = start_port; port <= end_port; port++) {
        int result = scan_port(host, port);
        if (result == 1) {
            printf("Port %d is open\n", port);
        }
    }

    _endthreadex(0);
    return 0;
}

void scan_ports(const char* host, int start_port, int end_port, int num_threads) {
    int ports_per_thread = (end_port - start_port + 1) / num_threads;
    int remaining_ports = (end_port - start_port + 1) % num_threads;
    int thread;
    HANDLE* scanThreads = malloc(num_threads * sizeof(HANDLE));
    ScanParams* scanParams = malloc(num_threads * sizeof(ScanParams));

    for (thread = 0; thread < num_threads; thread++) {
        scanParams[thread].host = host;
        scanParams[thread].start_port = start_port + thread * ports_per_thread;
        scanParams[thread].end_port = scanParams[thread].start_port + ports_per_thread - 1;

        if (thread == num_threads - 1) {
            // Assign remaining ports to the last thread
            scanParams[thread].end_port += remaining_ports;
        }

        scanThreads[thread] = (HANDLE)_beginthreadex(NULL, 0, scan_ports_thread, &scanParams[thread], 0, NULL);
    }

    // Wait for all threads to finish
    WaitForMultipleObjects(num_threads, scanThreads, TRUE, INFINITE);

    free(scanThreads);
    free(scanParams);
}

int main(int argc, char* argv[]) {
    if (argc < 3 || argc > 5) {
        printf("Usage: %s <host> <port/start_port> [end_port] [num_threads]\n", argv[0]);
        return 1;
    }

    const char* host = argv[1];
    int start_port = atoi(argv[2]);
    int end_port;
    int num_threads = 25;

    if (argc >= 4) {
        end_port = atoi(argv[3]);
        if (argc == 5) {
            num_threads = atoi(argv[4]);
        }
    } else {
        end_port = start_port;
    }

    if (start_port < 1 || start_port > MAX_PORTS || end_port < 1 || end_port > MAX_PORTS || start_port > end_port) {
        printf("Invalid port range.\n");
        return 1;
    }

    printf("Scanning ports %d to %d on host %s using %d thread(s)...\n", start_port, end_port, host, num_threads);
    scan_ports(host, start_port, end_port, num_threads);
    return 0;
}

A BOFH Generator in C

// gcc bofh.c -o bofh
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NUM_QUOTES 10

const char* bofh_quotes[NUM_QUOTES] = {
    "No, my powers can only be used for good.",
    "It must be a hardware problem.",
    "I'm sorry, we don't support that feature.",
    "That's a PEBCAK error (Problem Exists Between Chair And Keyboard).",
    "Have you tried turning it off and on again?",
    "The BOFH Excuse Server is down.",
    "It works for me.",
    "I'm afraid I can't help you with that.",
    "According to the manual, it should work.",
    "You must have done something wrong."
};

int main() {
    srand(time(NULL));  // seed the random number generator

    int random_index = rand() % NUM_QUOTES;
    const char* quote = bofh_quotes[random_index];

    printf("%s\n", quote);

    return 0;
}

Change Windows network share permissions from command line

Grant-SmbShareAccess -Name ShareName -AccountName Administrators -AccessRight Full -Force
Grant-SmbShareAccess -Name "Brother DW2710 series" -AccountName Everyone -AccessRight Change -Force

It appears that there is no pre-existing command line tool for managing permissions on existing shares beyond the initial setup. However, you can accomplish multiple grants if temporarily taking the shares offline is not a concern. In such a case, you have the option to utilize the following approach:

NET SHARE ShareName /DELETE /Y
NET SHARE ShareName=C:\TempShare /GRANT:Everyone,Change /GRANT:Administrators,Full /UNLIMITED