Delphi & Windows Firewall

// 7 Haziran 2009 // Delphi, Internet, İşletim Sistemi, Programlama

Firewall temel anlamı ile işletim sistemlerini daha güvenli kılmak için tasarlanmış programlardır.Modern işletim sistemlerinin hemen hemen hepsinde gömülü olarak bulunan bir firewall vardır. Güvenlik duvarı, ateş duvarı gibi isimler alan firewall’lar; makinamızda çalışan uygulamaların internete çıkışlarını denetleyen, dışarıdan içeri gelen TCP/UDP paketlerini çeşitli kurallara göre filtrelemeye çalışan uygulamalardır. Kimi zamanlarda yazdığımız uygulamalar, firewall’lar tarafından güvensiz içerik olarak algılanırlar ve blok edilmeye çalışılırlar. Eğer programınız network ortamında çalışıyor ve ortam bilgisayarları ile çeşitli protokoller üzerinden haberleşiyor ise, yada programınız internet’e erişmek durumunda ise; firewall’larla sıkıntı yaşamış olabilirsiniz.

Yazdığınız bir uygulamanın, uygulamayı geliştirdiğiniz makinada çalıştığı, ancak müşterinin makinasında çalışmadığı; yada erişmek istediğiniz network kaynaklarına erişemediği, internete çıkamadığı durumlarla karşılaştı iseniz, bu makalemizden istifade edebilirsiniz demektir. İşletim sistemi ile birlikte gelen Windows Firewall, nispeten basit bir güvenlik duvarı. Pek fazla ayarı ve detayı yok, ancak yine de paralı muadillerinin yaptıklarını mümkün mertebe yerine getiren bir program.

Bizim makalemiz, işletim sistemi ile birlikte gelen güvenlik duvarının programlanmasına yönelik olacak. Sizde taktir edersiniz ki, piyasada gerek donanımsal gerekse de yazılımsal pek çok farklı firewall mevcut, bizim yazacaklarımız onlara destek vermiyor olacak.

firewall_delphi_1

Yukarıdaki resimde, Windows Firewall’un genel ayarlarını görüyoruz. Bu ekranda, firewall’un açık yada kapalı olduğu bilgisi ve exception list’e izin verilip verilmeyeceği ayarını görüyoruz. Exception List, bizim firewall tarafından kontrol edilmesini istemediğimiz, network kaynaklarına yada internete erişimde firewall’un bloklamasından etkilenmeyecek uygulamalarımızın listesidir. Yukarıdaki resimde “Don’t allow exceptions” ayarı, bizim firewall kontrolünden uzakta tuttuğumuz programlarımızın dahi erişimlerinin firewall kontrolü altına yeniden alınabilmesi içindir. Bu ayar genellikle, taşınabilir bilgisayarınızla topluma açık mekanlarda internete bağlandığınız zaman yararlı olur. Aşağıda benim makinamda ki exception list görünüyor:

firewall_delphi_2

Windows Firewall ile biz sadece belirlediğimiz programlara değil, aynı zamanda belirlediğimiz bir port numarasına da izin verebiliriz. Bu özellik, genellikle client makinaların herhangi bir makinadaki SQL Server’a ulaşamamaları durumunda kullandığımız bir özellik. Yahut, makinanızda çalışan bir uygulamanın açmak istediği bir port ile internet üzerinden haberleşme yapmak durumunda kullanışlı olabilir. Örneğin, eMule dosya indirme programındaki gibi.

Bu makalemizde, Windows Firewall’dan; izin verilen programların ve izin verilen portların listesinin alınmasını, yeni bir program ve yeni bir port eklenmesini, firewall’un aktif/deaktif edilmesini ve yapılan değişikliklerin en son haline geri alınmasını göstermeye çalışacağız.

Bunun için yine COM programlamanın özelliklerinden yararlanacağız. İşletim sistemi ile birlikte gelen Windows Firewall’u Delphi’miz altında kullanabilmek için aşağıdaki resimde göreceğiniz üzere; gereken type library’i import edeceğiz.

firewall_delphi_0

Bu aşamadan sonra, Delphi varsayılan import klasöründe NetFwTypeLib_TLB.pas isminde bir dosya oluşturacaktır. Bu dosya, Windows Firewall nesnelerinin desteklediği arabirimlerin tanımlarını içerir.

Kullanacağımız en önemli arabirim, INetFwMgr isimli arabirim. Tüm erişimlerimizi bu arabirim üzerinden gerçekleştireceğiz. İlk olarak, Windows Firewall’a erişip, firewall’un aktif olup olmadığını sorgulayalım:

procedure TForm1.btnTestClick(Sender : TObject);
  FireWall : INetFwMgr;
begin
  CoInitialize(nil);

  FireWall := CreateOLEObject('HNetCfg.FwMgr') as INetFwMgr;

  if FireWall.LocalPolicy.CurrentProfile.FirewallEnabled
  then ShowMessage('Firewall is Enabled')
  else ShowMessage('Firewall is Disabled');

  FireWall := nil;
  CoUnInitialize;
end;

Yukarıda örneğimizde Windows Firewall nesnesine HNetCfg.FwMgr ismi üzerinden erişip gerekli kontrollerimizi yaptık. Peki, firewall’da erişim izni verilmiş olan uygulamaların(exception list) listesini nasıl alacağız ? Buyrun ona da yakından bakalım:

procedure TForm1.btnTestClick(Sender : TObject);
var
  FireWall : INetFwMgr;
  ExceptionList : INetFwAuthorizedApplications;
  Collection : IEnumVariant;
  tmp : OleVariant;
  dummy : Cardinal;
begin
  CoInitialize(nil);

  FireWall := CreateOLEObject('HNetCfg.FwMgr') as INetFwMgr;
  ExceptionList := FireWall.LocalPolicy.CurrentProfile.AuthorizedApplications;
  Collection := ExceptionList._NewEnum as IEnumVariant;
  
    while (Collection.Next(1, tmp, dummy) = S_OK) do
      Memo1.Lines.Add(tmp.Name + '->' + tmp.ProcessImageFileName + '->' + tmp.RemoteAddresses);

  Collection := nil;
  ExceptionList := nil;
  FireWall := nil;

  CoUnInitialize;    
end;

Yukarıdaki örneğimiz, INetFwMgr arabiriminin AuthorizedApplications arabirimine ulaşarak daha önce izin verilmiş uygulamarın listesini aldı ve bir TMemo bileşeni içinde gösterdi. Buna benzer bir yapıda, izin verilen port’ların listesini almak için kurabiliriz;

procedure TForm1.btnTestClick(Sender : TObject);
var
  FireWall : INetFwMgr;
  Collection  : IEnumVariant;
  tmp : OleVariant;
  dummy : Cardinal;
begin
  CoInitialize(nil);

  FireWall := CreateOLEObject('HNetCfg.FwMgr') as INetFwMgr;
  
  Collection := FireWall.LocalPolicy.CurrentProfile.GloballyOpenPorts._NewEnum as IEnumVariant;
  while (Collection.Next(1, tmp, dummy) = S_OK) do
      Memo1.Lines.Add(tmp.Name + '->' + InttoStr(Integer(tmp.Port)));

  Collection := nil;
  FireWall := nil;

  CoUnInitialize;    
end;

Gördüğünüz gibi karmaşık olmayan, ancak pek de akılda kalıcı olmayan bir yazım tarzına sahip. Hem daha sonralardaki kullanımlarımızda kolaylık olması adına, hemde onlarca satırı müteaddit defalar yazmamak için gelin biz bu fonksiyonaliteyi kapsayacak bir TFireWall sınıfı yazalım:

  TFireWallIPVersion  = (
                          Version4          = $00000000,
                          Version6          = $00000001,
                          VersionAny        = $00000002,
                          VersionMax        = $00000003
                        );
  TFireWallScope      = (
                          ScopeAll          = $00000000,
                          ScopeLocalSubnet  = $00000001,
                          ScopeCustom       = $00000002,
                          ScopeMax          = $00000003
                        );
  TFireWallProtocol   = (
                          ProtocolTCP = $00000006,
                          ProtocolUDP = $00000011
                        );

  TAuhtorizedApp = class
  private
    fName,
    fRemoteAddress,
    fProcessImageFileName : String;
    fEnabled              : Boolean;
    fIpVersion            : TFireWallIPVersion;
    fScope                : TFireWallScope;
  public
    constructor Create(
                        const AName,
                              ARemoteAddresses,
                              AProcessImageFileName : String;
                        const AEnabled : Boolean;
                        const AScope : TFireWallScope;
                        const AIpVersion : TFireWallIPVersion
                       );

    property Name                 : String              read fName;
    property RemoteAddresses      : String              read fRemoteAddress;
    property ProcessImageFileName : String              read fProcessImageFileName;
    property Enabled              : Boolean             read fEnabled;
    property Scope                : TFireWallScope      read fScope;
    property IpVersion            : TFireWallIPVersion  read fIpVersion;
  end;

  TOpenPort = class
  private
    fName,
    fRemoteAddress        : String;
    fEnabled,
    fBuiltIn              : Boolean;
    fIpVersion            : TFireWallIPVersion;
    fScope                : TFireWallScope;
    fProtocol             : TFireWallProtocol;
    fPort                 : Integer;
  public
    constructor Create(
                        const AName,
                              ARemoteAddresses : String;
                        const AEnabled : Boolean;
                        const AScope : TFireWallScope;
                        const AIpVersion : TFireWallIPVersion;
                        const AProtocol : TFireWallProtocol;
                        const APort : Integer
                       );

    property Name                 : String              read fName;
    property RemoteAddresses      : String              read fRemoteAddress;
    property Enabled              : Boolean             read fEnabled;
    property Scope                : TFireWallScope      read fScope;
    property IpVersion            : TFireWallIPVersion  read fIpVersion;

    property Protocol             : TFireWallProtocol   read fProtocol;
    property Port                 : Integer             read fPort;
  end;

  TFireWall = class
  private
    fFireWall                : INetFwMgr;
    fLocalPolicy             : INetFwPolicy;
    fProfile                 : INetFwProfile;
    fRemoteAdminSettings     : INetFwRemoteAdminSettings;
    fIcmpSettings            : INetFwIcmpSettings;
    fGloballyOpenPorts       : INetFwOpenPorts;
    fServices                : INetFwServices;
    fAuthorizedApplications  : INetFwAuthorizedApplications;

    function GetFireWallEnabled : Boolean;
    procedure SetFireWallEnabled(const Value : Boolean);

    function GetAllowExceptions : Boolean;
    procedure SetAllowExceptions(const Value : Boolean);

    function GetAllowNotifications : Boolean;
    procedure SetAllowNotifications(const Value : Boolean);

    function GetAuthorizedApplications : TStrings;
    function GetOpenPorts : TStrings;
  public
    constructor Create;
    destructor Destroy; override;

    procedure Restore;
    function ApplicationExists(const APath : String) : Boolean;
    function PortExists(const APort : Integer; const AProtocol : TFireWallProtocol) : Boolean;

    procedure AddApplication(const AName, APath : String);
    procedure RemoveApplication(const APath : String);

    procedure AddPort(const AName : String; const APort : Integer; const APortProtocol : TFireWallProtocol);
    procedure RemovePort(const APort : Integer; const APortProtocol : TFireWallProtocol);

    property Enabled                : Boolean   read GetFireWallEnabled     write SetFireWallEnabled;
    property AllowExceptions        : Boolean   read GetAllowExceptions     write SetAllowExceptions;
    property AllowNotifications     : Boolean   read GetAllowNotifications  write SetAllowNotifications;

    property AuthorizedApplications : TStrings  read GetAuthorizedApplications;
    property OpenPorts              : TStrings  read GetOpenPorts;
  end;

implementation

{ TFireWall }

constructor TFireWall.Create;
begin
  inherited;

  CoInitialize(nil);

  fFireWall := CreateOLEObject('HNetCfg.FwMgr') as INetFwMgr;
  if fFireWall <> nil then
  begin
    fLocalPolicy             := fFireWall.LocalPolicy;
    fProfile                 := fFireWall.LocalPolicy.CurrentProfile;
    fRemoteAdminSettings     := fFireWall.LocalPolicy.CurrentProfile.RemoteAdminSettings;
    fIcmpSettings            := fFireWall.LocalPolicy.CurrentProfile.IcmpSettings;
    fGloballyOpenPorts       := fFireWall.LocalPolicy.CurrentProfile.GloballyOpenPorts;
    fServices                := fFireWall.LocalPolicy.CurrentProfile.Services;
    fAuthorizedApplications  := fFireWall.LocalPolicy.CurrentProfile.AuthorizedApplications;
  end else raise Exception.Create('Firewall''a ulaşılamıyor.!');
end;

destructor TFireWall.Destroy;
begin
  fFireWall                := nil;
  fLocalPolicy             := nil;
  fProfile                 := nil;
  fRemoteAdminSettings     := nil;
  fIcmpSettings            := nil;
  fGloballyOpenPorts       := nil;
  fServices                := nil;
  fAuthorizedApplications  := nil;

  CoUninitialize;

  inherited;
end;


procedure TFireWall.AddApplication(const AName, APath: String);
var
  app : INetFwAuthorizedApplication;
begin
  if Trim(AName) = '' then
    raise Exception.Create('Lütfen bir isim belirtiniz.!');

  if not FileExists(APath) then
    raise Exception.Create('Belirtilen dosya bulunamadı.!');

  if not AllowExceptions then
    raise Exception.Create('Uygulama ekleme seçeneği devre dışı.!');

  app := CreateOleObject('HNetCfg.FwAuthorizedApplication') as INetFwAuthorizedApplication;
  try
    app.Name := AName;
    app.ProcessImageFileName := APath;
    app.IpVersion := TOleEnum(VersionAny);
    app.RemoteAddresses := '*';
    app.Scope := TOleEnum(ScopeAll);
    app.Enabled := true;

    fAuthorizedApplications.Add(app);
  finally
    app := nil;
  end;
end;

procedure TFireWall.AddPort(const AName: String; const APort: Integer;
  const APortProtocol: TFireWallProtocol);
var
  port : INetFwOpenPort;
begin
  if Trim(AName) = '' then
    raise Exception.Create('Lütfen bir isim belirtiniz.!');

  port := CreateOleObject('HNetCfg.FwOpenPort') as INetFwOpenPort;
  try
    port.Name := AName;
    port.IpVersion := TOleEnum(VersionAny);
    port.Protocol := TOleEnum(APortProtocol);
    port.Scope := TOleEnum(ScopeAll);
    port.Port := APort;
    port.RemoteAddresses := '*';
    port.Enabled := true;

    fGloballyOpenPorts.Add(port);
  finally
    port := nil;
  end;
end;

function TFireWall.ApplicationExists(const APath : String): Boolean;
var
  sList     : TStrings;
  iCounter  : Integer;
begin
  Result := false;

  sList := AuthorizedApplications;

  if sList <> nil then
    for iCounter := 0 to sList.Count - 1 do
      if sList.Objects[iCounter] <> nil then
        if sList.Objects[iCounter] is TAuhtorizedApp then
          if TAuhtorizedApp(sList.Objects[iCounter]).ProcessImageFileName = APath then
          begin
            Result := true;
            Break;
          end;
end;

function TFireWall.GetAllowExceptions: Boolean;
begin
  Result := false;

  if fProfile <> nil then
    Result := not fProfile.ExceptionsNotAllowed;
end;

function TFireWall.GetAllowNotifications: Boolean;
begin
  Result := false;

  if fProfile <> nil then
    Result := fProfile.NotificationsDisabled;
end;

function TFireWall.GetAuthorizedApplications: TStrings;
var
  apps      : IEnumVariant;
  app       : OleVariant;
  dummy     : Cardinal;
  iCounter  : Integer;
begin
  Result := TStringList.Create;

  apps := fAuthorizedApplications._NewEnum as IEnumVariant;
  while (apps.Next(1, app, dummy) = S_OK) do
  begin
    Result.AddObject(
             app.Name,
             TAuhtorizedApp.Create(
                                   app.Name,
                                   app.RemoteAddresses,
                                   app.ProcessImageFileName,
                                   app.Enabled,
                                   TFireWallScope(app.Scope),
                                   TFireWallIPVersion(app.IpVersion)
                                           )
                    );
  end;

  apps := nil;
end;

function TFireWall.GetFireWallEnabled: Boolean;
begin
  Result := false;

  if fProfile <> nil then
    Result := fProfile.FirewallEnabled;
end;

function TFireWall.GetOpenPorts: TStrings;
var
  ports     : IEnumVariant;
  port      : OleVariant;
  dummy     : Cardinal;
  iCounter  : Integer;
begin
  Result := TStringList.Create;

  ports := fProfile.GloballyOpenPorts._NewEnum as IEnumVariant;
  while (ports.Next(1, port, dummy) = S_OK) do
  begin
    Result.AddObject(
             port.Name,
             TOpenPort.Create(
                                port.Name,
                                port.RemoteAddresses,
                                port.Enabled,
                                TFireWallScope(port.Scope),
                                TFireWallIpVersion(port.IpVersion),
                                TFireWallProtocol(port.Protocol),
                                Integer(port.Port)
                                       )
                    );
  end;

  ports := nil;
end;

function TFireWall.PortExists(const APort: Integer; const AProtocol : TFireWallProtocol): Boolean;
var
  sList     : TStrings;
  iCounter  : Integer;
begin
  Result := false;

  sList := OpenPorts;

  if sList <> nil then
    for iCounter := 0 to sList.Count - 1 do
      if sList.Objects[iCounter] <> nil then
        if sList.Objects[iCounter] is TOpenPort then
          if (TOpenPort(sList.Objects[iCounter]).Port = APort) and
             (TOpenPort(sList.Objects[iCounter]).Protocol = AProtocol) then
             begin
              Result := true;
              Exit;
             end;
end;

procedure TFireWall.RemoveApplication(const APath : String);
begin
  if not FileExists(APath) then
    raise Exception.Create('Belirtilen dosya bulunamadı.!');

  if fAuthorizedApplications <> nil then
    fAuthorizedApplications.Remove(APath);
end;

procedure TFireWall.RemovePort(const APort: Integer;
  const APortProtocol: TFireWallProtocol);
begin
  if fGloballyOpenPorts <> nil then
    fGloballyOpenPorts.Remove(APort, TOleEnum(APortProtocol));
end;

procedure TFireWall.Restore;
begin
  if fFireWall <> nil then
    fFireWall.RestoreDefaults;
end;

procedure TFireWall.SetAllowExceptions(const Value: Boolean);
begin
  if fProfile <> nil then
    fProfile.ExceptionsNotAllowed := Value;
end;

procedure TFireWall.SetAllowNotifications(const Value: Boolean);
begin
  if fProfile <> nil then
    fProfile.NotificationsDisabled := Value;
end;

procedure TFireWall.SetFireWallEnabled(const Value: Boolean);
begin
  if fProfile <> nil then
    fProfile.FirewallEnabled := Value;
end;

{ TAuhtorizedApp }

constructor TAuhtorizedApp.Create(const AName, ARemoteAddresses,
  AProcessImageFileName: String; const AEnabled: Boolean;
  const AScope: TFireWallScope; const AIpVersion: TFireWallIPVersion);
begin
  inherited Create;

  fName := AName;
  fRemoteAddress := ARemoteAddresses;
  fProcessImageFileName := AProcessImageFileName;
  fEnabled := AEnabled;
  fScope := AScope;
  fIpVersion := AIpVersion;
end;

{ TOpenPort }

constructor TOpenPort.Create(const AName, ARemoteAddresses: String;
  const AEnabled : Boolean; const AScope: TFireWallScope;
  const AIpVersion: TFireWallIPVersion; const AProtocol: TFireWallProtocol;
  const APort: Integer);
begin
  inherited Create;

  fName := AName;
  fRemoteAddress := ARemoteAddresses;
  fEnabled := AEnabled;
  fScope := AScope;
  fIpVersion := AIpVersion;
  fProtocol := AProtocol;
  fPort := APort;
end;

Yukarıdaki kod örneğimizde; TAuhtorizedApp ve TOpenPort isimli sınıfları görüyoruz. Bu sınıflar; NetFwTypeLib_TLB.pas dosyası içindeki INetFwAuthorizedApplication ve INetFwOpenPort interface’lerinin karşılıkları olarak üretilmişler ve TFireWall sınıfımız içinde otomatikman oluşturulmuşlardır. Bu hâli ile TFireWall sınıfımız, Windows FireWall üzerinden izin verilen uygulama ve portların listesini alabildiği gibi, yeni uygulamalar ve portlar ekleyebilme gücüne sahiptir. Aynı zamanda Firewall’u açıp kapatabilen, izin verilen uygulamaların izinlerini devre dışı bırakabilen ve Windows Firewall’un herhangi bir uygulamayı blokladığında bizi uyarmasını sağlayan mekanizmayı kontrol edebildiğimiz bir sınıf olan TFireWall’un işinize yaramasını ümit ediyorum.

Saygılar, sevgiler..

“Delphi & Windows Firewall” için 8 Yorum

  1. Mustafa diyor ki:

    bu component guzel dusunulmus ama iyi niyetli insanlar icin. ayni yontemlerle trojanlar da kendilerine acik kapi olusturabilirler. Windows Firewall bu acidan pek de guzel bi secenek degil :)

    • Tuğrul HELVACI diyor ki:

      Bilginin her türlüsü iyiye ve kötüye kullanılabilir elbette. O da insanların ahlaki yaklaşımları ile ilgili. Biz bildiklerimizi paylaşır ve iyi hususlarda kullanmalarını ümit edebiliriz sadece. ;)

  2. Selman Erol diyor ki:

    Valla tuğrul abim iyi niyetli adamdır nerden bulmuş bilmiyorum ama iyi bulmuş iyide kullanır bu komponenti.

  3. Tuğrul HELVACI diyor ki:

    Sağolasın selmanım :) Ama component’i bir yerden bulmadım, benim imalatım :)

  4. Önder Önvermez diyor ki:

    Gerçekten class yazımını ve kullanımını öğreten iyi bir çalışma, geliştirilecek bir çok programa esin kaynağı olabilir. Emeğinize sağlık. Teşekkürler.

  5. Azat Cicek diyor ki:

    Bir cirpida okanabilecek,bilgilendirici,guzel bir makele olmus.Tesekkurler

  6. Gürcan diyor ki:

    Walla Tuğrulcuğum,
    senin yazılarını okurken
    delphiyi tam kavramadan bırakmaya yöneldiğimi düşünerek üzülüyorum..

Önder Önvermez için yorum yazın