Archive

Posts Tagged ‘linux’

Building a Wildcard Catch-All POP3 Mail Server on Ubuntu

Receive mail for any address on any subdomain — no per-account configuration required

Introduction

This guide walks through setting up a wildcard catch-all mail server on Ubuntu using Postfix and Dovecot. The goal is to receive email sent to any address on any subdomain of your domain — for example, anything@abc.yourdomain.com or test@xyz.yourdomain.com — without having to configure individual mailboxes in advance.

This is particularly useful for testing, disposable address systems, API integrations, and mail sink setups where you want to capture inbound mail programmatically. The server will not send mail — only receive it. Mail older than 24 hours is automatically purged.

Architecture Overview

The stack consists of three components working together:

  • Postfix — receives inbound SMTP and delivers to a local virtual mailbox
  • Dovecot — serves POP3 access to the mailbox
  • A single catch-all mailbox — all mail for all subdomains and addresses funnels into one Maildir

Rather than creating individual accounts, everything is routed to a single mailbox. A POP3 client connects with one username and password to retrieve all mail regardless of which address or subdomain it was sent to.

Part 1 — DNS Configuration

How Wildcard MX Records Work

MX records must point to a hostname, not an IP address directly. This means two DNS records are needed: an MX record pointing to a mail hostname, and an A record resolving that hostname to your server’s IP address.

Create the following records in your DNS provider (AWS Route 53 or equivalent):

Record NameType / Value
*.yourdomain.comMX — 10 mail.yourdomain.com
mail.yourdomain.comA — your.server.ip.address

The wildcard MX record *.yourdomain.com matches any single-level subdomain lookup. When a sending mail server looks up the MX record for abc.yourdomain.com, it matches the wildcard and is directed to mail.yourdomain.com, which in turn resolves to your server’s IP via the A record.

Note that the wildcard covers one subdomain level deep. Mail to anything@abc.yourdomain.com is covered. A deeper level such as anything@a.b.yourdomain.com would require a separate record.

Verifying DNS Records

From a Windows machine, use nslookup to verify records have propagated:

# Check the MX recordnslookup -type=MX abc.yourdomain.com
# Check the A record for the mail hostnslookup mail.yourdomain.com
# Query AWS nameservers directly (before public propagation)nslookup -type=NS yourdomain.comnslookup -type=MX abc.yourdomain.com ns-123.awsdns-45.com

You can also use dnschecker.org to check propagation across multiple global resolvers simultaneously.

Part 2 — Server Setup

Install Postfix and Dovecot

sudo apt updatesudo apt install postfix dovecot-pop3d -y

During the Postfix installation prompt, select Internet Site and enter your domain name (e.g. yourdomain.com) when asked for the mail name.

Configure Postfix

Edit the main Postfix configuration file:

sudo nano /etc/postfix/main.cf

Add or update the following values:

myhostname = mail.yourdomain.commydomain = yourdomain.com
# Leave mydestination empty — we use virtual mailboxes insteadmydestination =
# Accept mail for any subdomain matching the wildcardvirtual_mailbox_domains = regexp:/etc/postfix/virtual_domainsvirtual_mailbox_base = /var/mail/vhostsvirtual_mailbox_maps = regexp:/etc/postfix/virtual_mailboxvirtual_minimum_uid = 100virtual_uid_maps = static:5000virtual_gid_maps = static:5000
# Required to prevent open relaysmtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination

Create the virtual domains file — this regexp matches any subdomain of your domain:

sudo nano /etc/postfix/virtual_domains
/^\.+\.yourdomain\.com$/    OK

Create the virtual mailbox map — this catches all addresses and routes them to a single catchall mailbox:

sudo nano /etc/postfix/virtual_mailbox
/^.+@.+\.yourdomain\.com$/    catchall/

Rebuild the aliases database (required to avoid a startup warning):

newaliases

Create the Virtual Mail User and Mailbox

Postfix delivers mail as a dedicated system user (vmail). Create the user, group, and mailbox directory:

sudo groupadd -g 5000 vmailsudo useradd -u 5000 -g 5000 -d /var/mail/vhosts -s /sbin/nologin vmailsudo mkdir -p /var/mail/vhosts/catchallsudo chown -R vmail:vmail /var/mail/vhosts

Configure Dovecot for POP3

Enable the POP3 protocol in the main Dovecot config:

sudo nano /etc/dovecot/dovecot.conf
protocols = pop3

Set the mail location to the catchall Maildir:

sudo nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/vhosts/catchall

Allow plaintext authentication (suitable for internal/trusted use — see the TLS note at the end for public-facing deployments):

sudo nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = noauth_mechanisms = plain login
passdb {  driver = passwd-file  args = /etc/dovecot/users}
userdb {  driver = static  args = uid=5000 gid=5000 home=/var/mail/vhosts/catchall}

Create the Dovecot users file with your chosen credentials:

sudo nano /etc/dovecot/users
# Format: username:{PLAIN}passwordmailuser:{PLAIN}yourpasswordhere

Start the Services

sudo systemctl restart postfixsudo systemctl restart dovecot

Verify Postfix is running:

postfix status

Check the mail log for any errors:

tail -30 /var/log/mail.log

Part 3 — Firewall Configuration

Cloud Firewall (Linode / AWS / equivalent)

Open the following inbound ports in your cloud provider’s firewall. On Linode this is found under Networking > Firewalls in the dashboard. Changes apply immediately with no reboot required.

Port / ProtocolPurpose
22 TCPSSH (ensure this is always open)
25 TCPSMTP inbound (receiving mail)
110 TCPPOP3 (retrieving mail)

UFW on the Ubuntu Instance

sudo ufw allow 22/tcpsudo ufw allow 25/tcpsudo ufw allow 110/tcpsudo ufw enablesudo ufw status

Always confirm port 22 is allowed before enabling UFW to avoid locking yourself out of SSH.

Part 4 — Testing

Test SMTP Locally

From the server itself, connect to Postfix on port 25 and send a test message. Use 127.0.0.1 rather than localhost to avoid IPv6 connection issues:

telnet 127.0.0.1 25

You should immediately see the greeting banner:

220 mail.yourdomain.com ESMTP Postfix

Then send a test message interactively:

EHLO test.comMAIL FROM:<test@test.com>RCPT TO:<anything@abc.yourdomain.com>DATASubject: Test mail
Hello this is a test.QUIT

Each step should return a 250 OK response. The RCPT TO line is the critical one — if the wildcard regexp is configured correctly, Postfix will accept any subdomain address. After QUIT, verify the mail landed in the mailbox:

tail -20 /var/log/mail.logls -la /var/mail/vhosts/catchall/new/

You should see a file in the new/ directory — that is the email in Maildir format.

Test POP3 Locally

telnet 127.0.0.1 110

Dovecot should respond with:

+OK Dovecot (Ubuntu) ready.

Then authenticate and list messages:

USER mailuserPASS yourpasswordhereLISTRETR 1QUIT

A successful LIST response showing message count confirms the full chain is working: inbound SMTP via Postfix, delivery to virtual Maildir, and POP3 retrieval via Dovecot.

Part 5 — Automatic Mail Purge

To automatically delete mail older than 24 hours, add a cron job:

sudo crontab -e

Add the following line:

0 * * * * find /var/mail/vhosts/catchall -type f -mmin +1440 -delete

This runs every hour and removes any file in the catchall mailbox older than 1440 minutes (24 hours).

Optional — Silence the Backwards Compatibility Warning

Postfix logs a harmless warning about backwards-compatible default settings. To silence it:

postconf compatibility_level=3.6postfix reload

Security Notes

  • Port 110 transmits credentials in plaintext. For any public-facing deployment, configure Dovecot with TLS and use POP3S on port 995 instead.
  • The smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination setting prevents your server from acting as an open relay — do not remove this.
  • Consider rate limiting inbound SMTP connections if the server is publicly accessible to reduce spam load.
  • The vmail system user has no login shell (nologin) and cannot be used to access the system interactively.

Summary

With Postfix and Dovecot configured as described above, your server will:

  • Accept inbound SMTP for any address on any subdomain of your domain
  • Deliver all mail into a single catch-all Maildir with no per-account configuration
  • Expose all received mail via POP3 using a single username and password
  • Automatically purge mail older than 24 hours
  • Require no restart or reconfiguration when new subdomains or addresses are used

How to Detect and Fix Squid Proxy Abuse

Running an open HTTP proxy on the internet, even temporarily for testing, can quickly attract unwanted attention. Within minutes of deploying an unsecured Squid proxy, malicious actors can discover and abuse it for scanning, attacks, or hiding their origin. Here’s how to spot the warning signs and lock down your proxy.

Symptoms of Proxy Abuse

1. Proxy Stops Working

The most obvious symptom is that your proxy simply stops responding to legitimate requests. Connections timeout or hang indefinitely, even though the Squid service appears to be running.

2. Cache File Descriptor Warnings

When checking the Squid service status, you see repeated warnings like:

WARNING: Your cache is running out of file descriptors

This occurs because the proxy is handling far more concurrent connections than expected for a small test server.

3. Service Shows Active But Unresponsive

The systemd status shows Squid as “active (running)” with normal startup messages, but actual proxy requests fail:

bash

$ sudo systemctl status squid
● squid.service - Squid Web Proxy Server
Active: active (running)

Yet when you try to use it:

bash

$ curl -x http://your-proxy:8888 https://example.com
curl: (28) Failed to connect to example.com port 443 after 21060ms

4. High Memory or CPU Usage

A small EC2 instance (t2.micro or t3.micro) that should be mostly idle shows elevated resource consumption.

How to Verify Proxy Abuse

Check the Access Logs

The quickest way to confirm abuse is to examine the Squid access log:

bash

sudo tail -100 /var/log/squid/access.log

What to look for:

A healthy proxy used only by you should show:

  • One or two source IP addresses (yours)
  • Requests to legitimate domains
  • Occasional HTTPS CONNECT requests

An abused proxy will show:

  • Dozens of different source IP addresses
  • CONNECT requests to random IP addresses (not domain names)
  • Strange ports: SSH (22), Telnet (23), email ports (25, 587, 993, 110), random high ports
  • High frequency of requests

Example of Abuse

Here’s what an abused proxy log looks like:

1770200370.089 59842 172.234.115.25 TCP_TUNNEL/503 0 CONNECT 188.64.128.123:22
1770200370.089 59842 51.83.10.33 TCP_TUNNEL/503 0 CONNECT 188.64.132.53:443
1770200370.089 59841 172.234.115.25 TCP_TUNNEL/503 0 CONNECT 188.64.128.4:22
1770200370.089 59332 185.90.61.84 TCP_TUNNEL/503 0 CONNECT 188.64.129.251:8000
1770200370.089 214 91.202.74.22 TCP_TUNNEL/503 0 CONNECT 188.64.129.143:23
1770200370.191 579 51.83.10.33 TCP_TUNNEL/200 39 CONNECT 188.64.128.4:8021
1770200370.235 11227 51.83.10.33 TCP_TUNNEL/200 176 CONNECT 188.64.131.66:587

Notice:

  • Multiple unique source IPs
  • Connections to SSH (port 22), Telnet (port 23), SMTP (port 587)
  • Targets are raw IP addresses, not domain names
  • Hundreds of requests per minute

This is classic behavior of attackers using your proxy to scan the internet for vulnerable services.

Count Unique IPs

To see how many different IPs are using your proxy:

bash

sudo awk '{print $3}' /var/log/squid/access.log | sort | uniq -c | sort -rn | head -20

If you see more than a handful of IPs (especially if you’re the only legitimate user), your proxy is being abused.

Check Current Connections

See active connections to your proxy port:

bash

sudo netstat -tn | grep :8888

A legitimate test proxy should have 0-2 active connections. Dozens of connections indicate abuse.

How to Fix It Immediately

1. Lock Down the AWS Security Group

The fastest fix is to restrict access at the network level:

Via AWS Console:

  1. Navigate to EC2 → Security Groups
  2. Select the security group attached to your proxy instance
  3. Click “Edit inbound rules”
  4. Find the rule for your proxy port (e.g., 8888)
  5. Change Source from 0.0.0.0/0 to “My IP”
    • AWS will auto-detect and fill in your current public IP
  6. Click “Save rules”

The change takes effect immediately – no restart required.

2. Restart Squid to Kill Existing Connections

Even after locking down the security group, existing connections may persist:

bash

sudo systemctl restart squid

3. Clear the Logs

Start fresh to verify the abuse has stopped:

bash

# Stop Squid
sudo systemctl stop squid
# Clear logs
sudo truncate -s 0 /var/log/squid/access.log
sudo truncate -s 0 /var/log/squid/cache.log
# Clear cache if you're seeing file descriptor warnings
sudo rm -rf /var/spool/squid/*
sudo squid -z
# Restart
sudo systemctl start squid

4. Verify It’s Fixed

Watch the log in real-time:

bash

sudo tail -f /var/log/squid/access.log

If tail -f just sits there with no output, that’s good – it means no requests are coming through.

Now test from your own machine:

bash

curl -x http://your-proxy-ip:8888 https://ifconfig.me

You should immediately see your request appear in the log, and nothing else.

Prevention Best Practices

For Testing Environments

  1. Always use IP whitelisting – Never expose a proxy to 0.0.0.0/0 even for testing
  2. Use non-standard ports – While not security through obscurity, it reduces automated scanning
  3. Set up authentication – Even basic auth is better than nothing
  4. Monitor logs – Check periodically for unexpected traffic
  5. Terminate when done – Don’t leave test infrastructure running

Minimal Squid Config with Authentication

For slightly better security, add basic authentication:

bash

# Install htpasswd
sudo apt install apache2-utils
# Create password file
sudo htpasswd -c /etc/squid/passwords testuser
# Edit squid.conf
sudo nano /etc/squid/squid.conf

Add these lines:

http_port 8888
# Basic authentication
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
auth_param basic realm proxy
acl authenticated proxy_auth REQUIRED
http_access allow authenticated
http_access deny all
cache deny all

Restart Squid and now clients must authenticate:

bash

curl -x http://testuser:password@your-proxy:8888 https://example.com

For Production

If you need a production proxy:

  • Use a proper reverse proxy like nginx or HAProxy with TLS
  • Implement OAuth or certificate-based authentication
  • Use AWS PrivateLink or VPC peering instead of public exposure
  • Enable detailed logging and monitoring
  • Set up rate limiting
  • Consider managed solutions like AWS API Gateway or CloudFront

Conclusion

Open proxies are magnets for abuse. Automated scanners continuously sweep the internet looking for misconfigured proxies to exploit. The symptoms are often subtle – file descriptor warnings, poor performance, or timeouts – but the fix is straightforward: restrict access to only trusted IP addresses at the network level.

For testing purposes, AWS Security Groups provide the perfect solution: instant IP-based access control with no performance overhead. Combined with monitoring the Squid access logs, you can quickly detect and eliminate abuse before it impacts your testing or incurs unexpected costs.

Remember: if you’re running a temporary test proxy, lock it down to your IP from the start. It only takes minutes for automated scanners to find and abuse an open proxy.


Key Takeaways:

  • ✅ Always restrict proxy access via security groups/firewall rules
  • ✅ Monitor access logs for unexpected IP addresses
  • ✅ Watch for file descriptor warnings as an early sign of abuse
  • ✅ Clear logs and restart after securing to verify the fix
  • ✅ Terminate test infrastructure when finished to avoid ongoing costs

How to Extract #EXIF Data from an Image in .NET 8 with #MetadataExtractor

GIT REPO : https://github.com/infiniteloopltd/ExifResearch

When working with images, EXIF (Exchangeable Image File Format) data can provide valuable information such as the camera model, date and time of capture, GPS coordinates, and much more. Whether you’re building an image processing application or simply want to extract metadata for analysis, knowing how to retrieve EXIF data in a .NET environment is essential.

In this post, we’ll walk through how to extract EXIF data from an image in .NET 8 using the cross-platform MetadataExtractor library.

Why Use MetadataExtractor?

.NET’s traditional System.Drawing.Common library has limitations when it comes to cross-platform compatibility, particularly for non-Windows environments. The MetadataExtractor library, however, is a powerful and platform-independent solution for extracting metadata from various image formats, including EXIF data.

With MetadataExtractor, you can read EXIF metadata from images in a clean, efficient way, making it an ideal choice for .NET Core and .NET 8 developers working on cross-platform applications.

Step 1: Install MetadataExtractor

To begin, you need to add the MetadataExtractor NuGet package to your project. You can install it using the following command:

bashCopy codedotnet add package MetadataExtractor

This package supports EXIF, IPTC, XMP, and many other metadata formats from various image file types.

Step 2: Writing the Code to Extract EXIF Data

Now that the package is installed, let’s write some code to extract EXIF data from an image stored as a byte array.

Here is the complete function:

using System;
using System.Collections.Generic;
using System.IO;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;

public class ExifReader
{
public static Dictionary<string, string> GetExifData(byte[] imageBytes)
{
var exifData = new Dictionary<string, string>();

try
{
using var ms = new MemoryStream(imageBytes);
var directories = ImageMetadataReader.ReadMetadata(ms);

foreach (var directory in directories)
{
foreach (var tag in directory.Tags)
{
// Add tag name and description to the dictionary
exifData[tag.Name] = tag.Description;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error reading EXIF data: {ex.Message}");
}

return exifData;
}
}

How It Works:

  1. Reading Image Metadata: The function uses ImageMetadataReader.ReadMetadata to read all the metadata from the byte array containing the image.
  2. Iterating Through Directories and Tags: EXIF data is organized in directories (for example, the main EXIF data, GPS, and thumbnail directories). We iterate through these directories and their associated tags.
  3. Handling Errors: We wrap the logic in a try-catch block to ensure any potential errors (e.g., unsupported formats) are handled gracefully.

Step 3: Usage Example

To use this function, you can pass an image byte array to it. Here’s an example:

using System;
using System.IO;

class Program
{
static void Main()
{
// Replace with your byte array containing an image
byte[] imageBytes = File.ReadAllBytes("example.jpg");

var exifData = ExifReader.GetExifData(imageBytes);

foreach (var kvp in exifData)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
}
}

This code reads an image from the file system as a byte array and then uses the ExifReader.GetExifData method to extract the EXIF data. Finally, it prints out the EXIF tags and their descriptions.

Example Output:

If the image contains EXIF metadata, the output might look something like this:

  "Compression Type": "Baseline",
"Data Precision": "8 bits",
"Image Height": "384 pixels",
"Image Width": "512 pixels",
"Number of Components": "3",
"Component 1": "Y component: Quantization table 0, Sampling factors 2 horiz/2 vert",
"Component 2": "Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert",
"Component 3": "Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert",
"Make": "samsung",
"Model": "SM-G998B",
"Orientation": "Right side, top (Rotate 90 CW)",
"X Resolution": "72 dots per inch",
"Y Resolution": "72 dots per inch",
"Resolution Unit": "Inch",
"Software": "G998BXXU7EWCH",
"Date/Time": "2023:05:02 12:33:47",
"YCbCr Positioning": "Center of pixel array",
"Exposure Time": "1/33 sec",
"F-Number": "f/2.2",
"Exposure Program": "Program normal",
"ISO Speed Ratings": "640",
"Exif Version": "2.20",
"Date/Time Original": "2023:05:02 12:33:47",
"Date/Time Digitized": "2023:05:02 12:33:47",
"Time Zone": "+09:00",
"Time Zone Original": "+09:00",
"Shutter Speed Value": "1 sec",
"Aperture Value": "f/2.2",
"Exposure Bias Value": "0 EV",
"Max Aperture Value": "f/2.2",
"Metering Mode": "Center weighted average",
"Flash": "Flash did not fire",
"Focal Length": "2.2 mm",
"Sub-Sec Time": "404",
"Sub-Sec Time Original": "404",
"Sub-Sec Time Digitized": "404",
"Color Space": "sRGB",
"Exif Image Width": "4000 pixels",
"Exif Image Height": "3000 pixels",
"Exposure Mode": "Auto exposure",
"White Balance Mode": "Auto white balance",
"Digital Zoom Ratio": "1",
"Focal Length 35": "13 mm",
"Scene Capture Type": "Standard",
"Unique Image ID": "F12XSNF00NM",
"Compression": "JPEG (old-style)",
"Thumbnail Offset": "824 bytes",
"Thumbnail Length": "49594 bytes",
"Number of Tables": "4 Huffman tables",
"Detected File Type Name": "JPEG",
"Detected File Type Long Name": "Joint Photographic Experts Group",
"Detected MIME Type": "image/jpeg",
"Expected File Name Extension": "jpg"

This is just a small sample of the information EXIF can store. Depending on the camera and settings, you may find data on GPS location, white balance, focal length, and more.

Why Use EXIF Data?

EXIF data can be valuable in various scenarios:

  • Image processing: Automatically adjust images based on camera settings (e.g., ISO or exposure time).
  • Data analysis: Track when and where photos were taken, especially when handling large datasets of images.
  • Digital forensics: Verify image authenticity by analyzing EXIF metadata for manipulation or alterations.

Conclusion

With the MetadataExtractor library, extracting EXIF data from an image is straightforward and cross-platform compatible. Whether you’re building a photo management app, an image processing tool, or just need to analyze metadata, this approach is an efficient solution for working with EXIF data in .NET 8.

By using this solution, you can extract a wide range of metadata from images, making your applications smarter and more capable. Give it a try and unlock the hidden data in your images!