Index: /trunk/BNC/CHANGELOG.md
===================================================================
--- /trunk/BNC/CHANGELOG.md	(revision 11127)
+++ /trunk/BNC/CHANGELOG.md	(revision 11128)
@@ -58,4 +58,8 @@
 - FIXED: Encoding of new RTCM-SSR metadata with more than 30 additional parameter bits
 - CHANGED: Help text of 'Ignore SSL authorization errors' explains that the server is then not authenticated
+- CHANGED: UDP and RTSP/RTP streams: datagrams are accepted only from the Ntrip Broadcaster; streams without Ntrip ('UN') accept only the sender given as host in the stream URL, any sender with 127.0.0.1 (as written by 'Add Stream - Coming from UDP Port')
+- CHANGED: The configuration file (contains passwords) is saved readable for the owner only
+- FIXED: Upload: any caster answer containing '200' (e.g. in a header of a rejection) was taken as success; now the status line is checked
+- FIXED: Raw file input (--file): a station ID with a path led to output files outside the output directory; invalid chunk sizes are rejected
 
 ## 2.13.7 (2026-07-31)
Index: /trunk/BNC/src/bnchelp.html
===================================================================
--- /trunk/BNC/src/bnchelp.html	(revision 11127)
+++ /trunk/BNC/src/bnchelp.html	(revision 11128)
@@ -10321,4 +10321,10 @@
     Streams directly received at a UDP port show up with a 'UN' for 'UDP, No Ntrip' in the 'Streams' canvas section on
     BNC's main window. Latitude and longitude are to be entered just for informal reasons.
+  </p>
+  <p>
+    BNC accepts the UDP datagrams of any sender at that port, so anybody able to reach it can feed in data. To accept
+    only the datagrams of one sender, replace '127.0.0.1' in the stream's URL ('mountPoints' option, e.g.
+    '//127.0.0.1:2101/FFMJ00DEU ...') by the sender's IP address or host name, e.g. '//192.168.1.20:2101/FFMJ00DEU ...'.
+    In the Ntrip modes 'U' (UDP) and 'R' (RTSP/RTP), BNC accepts datagrams only from the Ntrip Broadcaster.
   <p>
 
Index: /trunk/BNC/src/bncnetqueryrtp.cpp
===================================================================
--- /trunk/BNC/src/bncnetqueryrtp.cpp	(revision 11127)
+++ /trunk/BNC/src/bncnetqueryrtp.cpp	(revision 11128)
@@ -77,18 +77,29 @@
 void bncNetQueryRtp::waitForReadyRead(QByteArray& outData) {
 
-  // Wait Loop
-  // ---------
-  if (!_udpSocket->hasPendingDatagrams()) {
-    _eventLoop->exec();
-  }
-
-  // Append Data
-  // -----------
-  QByteArray datagram;
-  datagram.resize(_udpSocket->pendingDatagramSize());
-  _udpSocket->readDatagram(datagram.data(), datagram.size());
-
-  if (datagram.size() > 12) {
-    outData.append(datagram.mid(12));
+  while (true) {
+
+    // Wait Loop
+    // ---------
+    if (!_udpSocket->hasPendingDatagrams()) {
+      _eventLoop->exec();
+      if (!_udpSocket->hasPendingDatagrams()) { // stopped
+        return;
+      }
+    }
+
+    // Append Data, only from the RTSP server (anybody else could feed in data)
+    // ------------------------------------------------------------------------
+    QByteArray datagram;
+    QHostAddress sender;
+    datagram.resize(_udpSocket->pendingDatagramSize());
+    _udpSocket->readDatagram(datagram.data(), datagram.size(), &sender);
+    if (!sender.isEqual(_serverAddress, QHostAddress::ConvertV4MappedToIPv4)) {
+      continue;
+    }
+
+    if (datagram.size() > 12) {
+      outData.append(datagram.mid(12));
+    }
+    return;
   }
 }
@@ -126,4 +137,5 @@
   // --------------
   if (_socket->waitForConnected(timeOut)) {
+    _serverAddress = _socket->peerAddress();
     QString uName = QUrl::fromPercentEncoding(_url.userName().toLatin1());
     QString passW = QUrl::fromPercentEncoding(_url.password().toLatin1());
Index: /trunk/BNC/src/bncnetqueryrtp.h
===================================================================
--- /trunk/BNC/src/bncnetqueryrtp.h	(revision 11127)
+++ /trunk/BNC/src/bncnetqueryrtp.h	(revision 11128)
@@ -2,4 +2,5 @@
 #define BNCNETQUERYRTP_H
 
+#include <QHostAddress>
 #include <QUdpSocket>
 
@@ -27,4 +28,5 @@
   QByteArray  _session;
   int         _CSeq;
+  QHostAddress _serverAddress; // RTP data accepted only from here
 };
 
Index: /trunk/BNC/src/bncnetqueryudp.cpp
===================================================================
--- /trunk/BNC/src/bncnetqueryudp.cpp	(revision 11127)
+++ /trunk/BNC/src/bncnetqueryudp.cpp	(revision 11128)
@@ -75,21 +75,32 @@
 void bncNetQueryUdp::waitForReadyRead(QByteArray& outData) {
 
-  // Wait Loop
-  // ---------
-  if (!_udpSocket->hasPendingDatagrams()) {
-    _eventLoop->exec();
-  }
+  while (true) {
 
-  // Append Data
-  // -----------
-  QByteArray datagram;
-  datagram.resize(_udpSocket->pendingDatagramSize());
-  _udpSocket->readDatagram(datagram.data(), datagram.size());
+    // Wait Loop
+    // ---------
+    if (!_udpSocket->hasPendingDatagrams()) {
+      _eventLoop->exec();
+      if (!_udpSocket->hasPendingDatagrams()) { // stopped
+        return;
+      }
+    }
 
-  if (datagram.size() > 12) {
-    outData.append(datagram.mid(12));
-  }
-  else {
-    _status = error;
+    // Append Data, only from the caster (anybody else could feed in data)
+    // -------------------------------------------------------------------
+    QByteArray datagram;
+    QHostAddress sender;
+    datagram.resize(_udpSocket->pendingDatagramSize());
+    _udpSocket->readDatagram(datagram.data(), datagram.size(), &sender);
+    if (!sender.isEqual(_address, QHostAddress::ConvertV4MappedToIPv4)) {
+      continue;
+    }
+
+    if (datagram.size() > 12) {
+      outData.append(datagram.mid(12));
+    }
+    else {
+      _status = error;
+    }
+    return;
   }
 }
@@ -156,4 +167,5 @@
 
     _udpSocket->writeDatagram(rtpbuffer, 12 + reqStr.size(), _address, _port);
+    free(rtpbuffer);
 
     // Wait for Reply, read Session Number
Index: /trunk/BNC/src/bncnetqueryudp0.cpp
===================================================================
--- /trunk/BNC/src/bncnetqueryudp0.cpp	(revision 11127)
+++ /trunk/BNC/src/bncnetqueryudp0.cpp	(revision 11128)
@@ -14,4 +14,6 @@
  *
  * -----------------------------------------------------------------------*/
+
+#include <QHostInfo>
 
 #include "bncnetqueryudp0.h"
@@ -47,17 +49,34 @@
 void bncNetQueryUdp0::waitForReadyRead(QByteArray& outData) {
 
-  // Wait Loop
-  // ---------
-  if (!_udpSocket->hasPendingDatagrams()) {
-    _eventLoop->exec();
+  if (!_udpSocket) {
+    return;
   }
 
-  // Append Data
-  // -----------
-  QByteArray datagram;
-  datagram.resize(_udpSocket->pendingDatagramSize());
-  _udpSocket->readDatagram(datagram.data(), datagram.size());
+  while (true) {
 
-  outData.append(datagram);
+    // Wait Loop
+    // ---------
+    if (!_udpSocket->hasPendingDatagrams()) {
+      _eventLoop->exec();
+      if (!_udpSocket->hasPendingDatagrams()) { // stopped
+        return;
+      }
+    }
+
+    // Append Data, only from the accepted senders
+    // -------------------------------------------
+    QByteArray datagram;
+    QHostAddress sender;
+    datagram.resize(_udpSocket->pendingDatagramSize());
+    _udpSocket->readDatagram(datagram.data(), datagram.size(), &sender);
+    bool accepted = _senders.isEmpty();
+    for (int ii = 0; !accepted && ii < _senders.size(); ii++) {
+      accepted = sender.isEqual(_senders[ii], QHostAddress::ConvertV4MappedToIPv4);
+    }
+    if (accepted) {
+      outData.append(datagram);
+      return;
+    }
+  }
 }
 
@@ -67,4 +86,25 @@
 
   _status = running;
+
+  // Host of the URL: sender whose datagrams are accepted; 127.0.0.1 (as
+  // written by the 'Add Stream - Coming from UDP Port' dialog), localhost
+  // or 0.0.0.0: datagrams from any sender
+  _senders.clear();
+  QString host = url.host();
+  if (!host.isEmpty() && host != "127.0.0.1" && host != "localhost" && host != "0.0.0.0") {
+    QHostAddress address;
+    if (address.setAddress(host)) {
+      _senders << address;
+    }
+    else {
+      _senders = QHostInfo::fromName(host).addresses();
+      if (_senders.isEmpty()) {
+        emit newMessage(url.path().toLatin1().replace(0,1,"") +
+                        ": Cannot resolve UDP sender " + host.toLatin1(), true);
+        _status = error;
+        return;
+      }
+    }
+  }
 
   delete _udpSocket;
Index: /trunk/BNC/src/bncnetqueryudp0.h
===================================================================
--- /trunk/BNC/src/bncnetqueryudp0.h	(revision 11127)
+++ /trunk/BNC/src/bncnetqueryudp0.h	(revision 11128)
@@ -2,4 +2,6 @@
 #define BNCNETQUERYUDP0_H
 
+#include <QHostAddress>
+#include <QList>
 #include <QUdpSocket>
 
@@ -20,4 +22,5 @@
   QUdpSocket*  _udpSocket;
   QEventLoop*  _eventLoop;
+  QList<QHostAddress> _senders; // accepted senders, empty: any
 };
 
Index: /trunk/BNC/src/bncrawfile.cpp
===================================================================
--- /trunk/BNC/src/bncrawfile.cpp	(revision 11127)
+++ /trunk/BNC/src/bncrawfile.cpp	(revision 11128)
@@ -138,8 +138,19 @@
       BNC_CORE->setDateAndTimeGPS(QDateTime(QDateTime::fromString(lst.value(0), Qt::ISODate)));
       
+      // the station ID becomes part of output file names: no path separators
       _staID  = lst.value(1).toLatin1();
+      for (int ii = 0; ii < _staID.size(); ii++) {
+        if (_staID[ii] == '/' || _staID[ii] == '\\' || (unsigned char)_staID[ii] < 0x20) {
+          _staID[ii] = '_';
+        }
+      }
       _format = lst.value(2).toLatin1();
-      int nBytes = lst.value(3).toInt();
-      
+      bool ok;
+      int nBytes = lst.value(3).trimmed().toInt(&ok);
+      if (!ok || nBytes < 0 || nBytes > (1 << 24)) {
+        BNC_CORE->slotMessage("Raw file: invalid chunk header: " + line.trimmed().left(80).toLatin1(), true);
+        return data;
+      }
+
       data = _inpFile->read(nBytes);
       
Index: /trunk/BNC/src/bncsettings.cpp
===================================================================
--- /trunk/BNC/src/bncsettings.cpp	(revision 11127)
+++ /trunk/BNC/src/bncsettings.cpp	(revision 11128)
@@ -15,4 +15,5 @@
  * -----------------------------------------------------------------------*/
 
+#include <QFile>
 #include <QSettings>
 
@@ -272,3 +273,6 @@
 
     settings.sync();
-}
+
+    // The file contains passwords: readable for the owner only
+    QFile::setPermissions(BNC_CORE->confFileName(), QFile::ReadOwner | QFile::WriteOwner);
+}
Index: /trunk/BNC/src/upload/bncuploadcaster.cpp
===================================================================
--- /trunk/BNC/src/upload/bncuploadcaster.cpp	(revision 11127)
+++ /trunk/BNC/src/upload/bncuploadcaster.cpp	(revision 11128)
@@ -24,4 +24,12 @@
 
 using namespace std;
+
+// Status line of the caster/proxy answer is "HTTP/1.x 200 ..." or "ICY 200 OK"
+////////////////////////////////////////////////////////////////////////////
+static bool statusOk(const QByteArray& ans) {
+  QList<QByteArray> status = ans.left(ans.indexOf("\r\n")).split(' ');
+  return status.size() >= 2 && status[1] == "200" &&
+         (status[0].startsWith("HTTP/") || status[0] == "ICY");
+}
 
 // Constructor
@@ -284,5 +292,5 @@
 
       QByteArray ans = _outSocket->readAll();
-      if (ans.indexOf("200") == -1) {
+      if (!statusOk(ans)) {
         int l = ans.indexOf("\r\n", 0);
         emit(newMessage("Proxy: Connection broken for " + _mountpoint.toLatin1() + "@" +
@@ -331,5 +339,5 @@
    QByteArray ans = _outSocket->readAll();
 
-  if (ans.indexOf("200") == -1) {
+  if (!statusOk(ans)) {
     delete _outSocket; _outSocket = 0;
     int l = ans.indexOf("\r\n", 0);
